@medialane/ui 0.328.0 → 0.329.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account/input-otp.d.cts +2 -2
- package/dist/components/account/input-otp.d.ts +2 -2
- package/dist/components/asset-card.cjs +4 -4
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.js +4 -4
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/asset-marketplace-panel.cjs +23 -26
- package/dist/components/asset-marketplace-panel.cjs.map +1 -1
- package/dist/components/asset-marketplace-panel.js +23 -26
- package/dist/components/asset-marketplace-panel.js.map +1 -1
- package/dist/components/badge.d.cts +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/coin-row.cjs +3 -3
- package/dist/components/coin-row.cjs.map +1 -1
- package/dist/components/coin-row.js +3 -3
- package/dist/components/coin-row.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/listing-card.cjs +2 -14
- package/dist/components/listing-card.cjs.map +1 -1
- package/dist/components/listing-card.js +2 -14
- package/dist/components/listing-card.js.map +1 -1
- package/dist/components/price-display.cjs +115 -0
- package/dist/components/price-display.cjs.map +1 -0
- package/dist/components/price-display.d.cts +44 -0
- package/dist/components/price-display.d.ts +44 -0
- package/dist/components/price-display.js +91 -0
- package/dist/components/price-display.js.map +1 -0
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- package/dist/components/token-card.cjs +4 -4
- package/dist/components/token-card.cjs.map +1 -1
- package/dist/components/token-card.js +4 -4
- package/dist/components/token-card.js.map +1 -1
- package/dist/utils/format.cjs +9 -0
- package/dist/utils/format.cjs.map +1 -1
- package/dist/utils/format.d.cts +2 -1
- package/dist/utils/format.d.ts +2 -1
- package/dist/utils/format.js +8 -0
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
- package/package.json +1 -1
- package/dist/components/dual-price.cjs +0 -164
- package/dist/components/dual-price.cjs.map +0 -1
- package/dist/components/dual-price.d.cts +0 -53
- package/dist/components/dual-price.d.ts +0 -53
- package/dist/components/dual-price.js +0 -138
- package/dist/components/dual-price.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CurrencyIcon, hasCurrencyIcon } from "./currency-icon.js";
|
|
4
|
+
import { cn } from "../utils/cn.js";
|
|
5
|
+
import { formatCompactPrice, formatDisplayPrice, isStableCurrency } from "../utils/format.js";
|
|
6
|
+
const SCALES = {
|
|
7
|
+
hero: {
|
|
8
|
+
gap: "gap-x-4 gap-y-2",
|
|
9
|
+
icon: 26,
|
|
10
|
+
amount: "text-3xl",
|
|
11
|
+
name: "text-lg",
|
|
12
|
+
pill: "px-3 py-1 text-sm",
|
|
13
|
+
showName: true,
|
|
14
|
+
compact: false
|
|
15
|
+
},
|
|
16
|
+
row: {
|
|
17
|
+
gap: "gap-x-3 gap-y-1",
|
|
18
|
+
icon: 14,
|
|
19
|
+
amount: "text-sm",
|
|
20
|
+
name: "text-xs",
|
|
21
|
+
pill: "px-2 py-0.5 text-xs",
|
|
22
|
+
showName: true,
|
|
23
|
+
compact: false
|
|
24
|
+
},
|
|
25
|
+
card: {
|
|
26
|
+
gap: "gap-x-2.5",
|
|
27
|
+
icon: 14,
|
|
28
|
+
amount: "text-base",
|
|
29
|
+
name: "text-xs",
|
|
30
|
+
pill: "px-2 py-0.5 text-xs",
|
|
31
|
+
showName: false,
|
|
32
|
+
compact: true
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
function usdLabel(usdValue, compact) {
|
|
36
|
+
let amount = usdValue.replace("$", "");
|
|
37
|
+
if (compact) {
|
|
38
|
+
const n = Number(amount.replace(/,/g, ""));
|
|
39
|
+
if (isFinite(n) && n >= 1e3) amount = formatCompactPrice(n);
|
|
40
|
+
}
|
|
41
|
+
return amount.startsWith("<") ? `${amount} USD` : `\u2248 ${amount} USD`;
|
|
42
|
+
}
|
|
43
|
+
function PriceDisplay({
|
|
44
|
+
amountFormatted,
|
|
45
|
+
currency,
|
|
46
|
+
usdValue,
|
|
47
|
+
scale,
|
|
48
|
+
trailing,
|
|
49
|
+
className,
|
|
50
|
+
pillClassName
|
|
51
|
+
}) {
|
|
52
|
+
if (!amountFormatted) return null;
|
|
53
|
+
const s = SCALES[scale];
|
|
54
|
+
const amount = s.compact ? formatCompactPrice(amountFormatted) : formatDisplayPrice(amountFormatted);
|
|
55
|
+
const showName = !!currency && (s.showName || !hasCurrencyIcon(currency));
|
|
56
|
+
const showPill = !!usdValue && !isStableCurrency(currency);
|
|
57
|
+
return /* @__PURE__ */ jsxs(
|
|
58
|
+
"span",
|
|
59
|
+
{
|
|
60
|
+
className: cn(
|
|
61
|
+
"inline-flex items-center tabular-nums",
|
|
62
|
+
s.gap,
|
|
63
|
+
scale === "hero" ? "flex-wrap" : "flex-nowrap whitespace-nowrap",
|
|
64
|
+
className
|
|
65
|
+
),
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
68
|
+
/* @__PURE__ */ jsx(CurrencyIcon, { symbol: currency, size: s.icon }),
|
|
69
|
+
/* @__PURE__ */ jsx("span", { className: cn("font-semibold tracking-tight text-foreground", s.amount), children: amount }),
|
|
70
|
+
showName ? /* @__PURE__ */ jsx("span", { className: cn("font-semibold text-muted-foreground", s.name), children: currency }) : null
|
|
71
|
+
] }),
|
|
72
|
+
showPill ? /* @__PURE__ */ jsx(
|
|
73
|
+
"span",
|
|
74
|
+
{
|
|
75
|
+
className: cn(
|
|
76
|
+
"inline-flex items-center rounded-full bg-foreground/[0.06] font-medium text-muted-foreground",
|
|
77
|
+
s.pill,
|
|
78
|
+
pillClassName
|
|
79
|
+
),
|
|
80
|
+
children: usdLabel(usdValue, s.compact)
|
|
81
|
+
}
|
|
82
|
+
) : null,
|
|
83
|
+
trailing
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
PriceDisplay
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=price-display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/price-display.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon, hasCurrencyIcon } from \"./currency-icon.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatCompactPrice, formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\nconst SCALES = {\n hero: {\n gap: \"gap-x-4 gap-y-2\",\n icon: 26,\n amount: \"text-3xl\",\n name: \"text-lg\",\n pill: \"px-3 py-1 text-sm\",\n showName: true,\n compact: false,\n },\n row: {\n gap: \"gap-x-3 gap-y-1\",\n icon: 14,\n amount: \"text-sm\",\n name: \"text-xs\",\n pill: \"px-2 py-0.5 text-xs\",\n showName: true,\n compact: false,\n },\n card: {\n gap: \"gap-x-2.5\",\n icon: 14,\n amount: \"text-base\",\n name: \"text-xs\",\n pill: \"px-2 py-0.5 text-xs\",\n showName: false,\n compact: true,\n },\n} as const;\n\nexport type PriceScale = keyof typeof SCALES;\n\nfunction usdLabel(usdValue: string, compact: boolean): string {\n let amount = usdValue.replace(\"$\", \"\");\n if (compact) {\n const n = Number(amount.replace(/,/g, \"\"));\n if (isFinite(n) && n >= 1000) amount = formatCompactPrice(n);\n }\n return amount.startsWith(\"<\") ? `${amount} USD` : `≈ ${amount} USD`;\n}\n\nexport function PriceDisplay({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n className,\n pillClassName,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: PriceScale;\n trailing?: ReactNode;\n className?: string;\n pillClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = SCALES[scale];\n const amount = s.compact ? formatCompactPrice(amountFormatted) : formatDisplayPrice(amountFormatted);\n const showName = !!currency && (s.showName || !hasCurrencyIcon(currency));\n const showPill = !!usdValue && !isStableCurrency(currency);\n\n return (\n <span\n className={cn(\n \"inline-flex items-center tabular-nums\",\n s.gap,\n scale === \"hero\" ? \"flex-wrap\" : \"flex-nowrap whitespace-nowrap\",\n className\n )}\n >\n <span className=\"inline-flex items-center gap-1.5\">\n <CurrencyIcon symbol={currency} size={s.icon} />\n <span className={cn(\"font-semibold tracking-tight text-foreground\", s.amount)}>{amount}</span>\n {showName ? <span className={cn(\"font-semibold text-muted-foreground\", s.name)}>{currency}</span> : null}\n </span>\n {showPill ? (\n <span\n className={cn(\n \"inline-flex items-center rounded-full bg-foreground/[0.06] font-medium text-muted-foreground\",\n s.pill,\n pillClassName\n )}\n >\n {usdLabel(usdValue!, s.compact)}\n </span>\n ) : null}\n {trailing}\n </span>\n );\n}\n"],"mappings":";AAgFM,SACE,KADF;AA7EN,SAAS,cAAc,uBAAuB;AAC9C,SAAS,UAAU;AACnB,SAAS,oBAAoB,oBAAoB,wBAAwB;AAEzE,MAAM,SAAS;AAAA,EACb,MAAM;AAAA,IACJ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,MAAM;AAAA,IACJ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AACF;AAIA,SAAS,SAAS,UAAkB,SAA0B;AAC5D,MAAI,SAAS,SAAS,QAAQ,KAAK,EAAE;AACrC,MAAI,SAAS;AACX,UAAM,IAAI,OAAO,OAAO,QAAQ,MAAM,EAAE,CAAC;AACzC,QAAI,SAAS,CAAC,KAAK,KAAK,IAAM,UAAS,mBAAmB,CAAC;AAAA,EAC7D;AACA,SAAO,OAAO,WAAW,GAAG,IAAI,GAAG,MAAM,SAAS,UAAK,MAAM;AAC/D;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,MAAI,CAAC,gBAAiB,QAAO;AAC7B,QAAM,IAAI,OAAO,KAAK;AACtB,QAAM,SAAS,EAAE,UAAU,mBAAmB,eAAe,IAAI,mBAAmB,eAAe;AACnG,QAAM,WAAW,CAAC,CAAC,aAAa,EAAE,YAAY,CAAC,gBAAgB,QAAQ;AACvE,QAAM,WAAW,CAAC,CAAC,YAAY,CAAC,iBAAiB,QAAQ;AAEzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,EAAE;AAAA,QACF,UAAU,SAAS,cAAc;AAAA,QACjC;AAAA,MACF;AAAA,MAEA;AAAA,6BAAC,UAAK,WAAU,oCACd;AAAA,8BAAC,gBAAa,QAAQ,UAAU,MAAM,EAAE,MAAM;AAAA,UAC9C,oBAAC,UAAK,WAAW,GAAG,gDAAgD,EAAE,MAAM,GAAI,kBAAO;AAAA,UACtF,WAAW,oBAAC,UAAK,WAAW,GAAG,uCAAuC,EAAE,IAAI,GAAI,oBAAS,IAAU;AAAA,WACtG;AAAA,QACC,WACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,EAAE;AAAA,cACF;AAAA,YACF;AAAA,YAEC,mBAAS,UAAW,EAAE,OAAO;AAAA;AAAA,QAChC,IACE;AAAA,QACH;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "left" | "right" | "bottom" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -10,7 +10,7 @@ declare const SheetClose: React.ForwardRefExoticComponent<SheetPrimitive.DialogC
|
|
|
10
10
|
declare const SheetPortal: React.FC<SheetPrimitive.DialogPortalProps>;
|
|
11
11
|
declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<SheetPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
12
12
|
declare const sheetVariants: (props?: ({
|
|
13
|
-
side?: "
|
|
13
|
+
side?: "left" | "right" | "bottom" | "top" | null | undefined;
|
|
14
14
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
15
15
|
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {
|
|
16
16
|
overlayClassName?: string;
|
|
@@ -40,7 +40,7 @@ var import_dropdown_menu = require("./dropdown-menu.js");
|
|
|
40
40
|
var import_cn = require("../utils/cn.js");
|
|
41
41
|
var import_format = require("../utils/format.js");
|
|
42
42
|
var import_currency_icon = require("./currency-icon.js");
|
|
43
|
-
var
|
|
43
|
+
var import_price_display = require("./price-display.js");
|
|
44
44
|
var import_ip_type_badge = require("./ip-type-badge.js");
|
|
45
45
|
var import_animated_token_media = require("./animated-token-media.js");
|
|
46
46
|
var import_living_render_collections = require("../data/living-render-collections.js");
|
|
@@ -109,13 +109,13 @@ function TokenCard({
|
|
|
109
109
|
] }),
|
|
110
110
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-3 pt-2.5 pb-4 flex-1 space-y-1", children: [
|
|
111
111
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-base font-bold line-clamp-2 leading-snug", children: name }),
|
|
112
|
-
listingOrder && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
113
|
-
|
|
112
|
+
listingOrder && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
113
|
+
import_price_display.PriceDisplay,
|
|
114
114
|
{
|
|
115
115
|
amountFormatted: listingOrder.price.formatted,
|
|
116
116
|
currency: listingOrder.price.currency,
|
|
117
117
|
usdValue,
|
|
118
|
-
|
|
118
|
+
scale: "card"
|
|
119
119
|
}
|
|
120
120
|
) })
|
|
121
121
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceChipContent } from \"./dual-price.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base group relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1 space-y-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n {listingOrder && (\n <p className=\"flex items-center justify-end gap-1.5 text-sm tabular-nums\">\n <PriceChipContent\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n tone=\"card\"\n />\n </p>\n )}\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"px-2.5\", hasPrimaryAction ? \"shrink-0\" : \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n View\n </Link>\n\n {isOwner ? (\n !listingOrder ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n Sell\n </button>\n ) : null\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : null}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n Sell\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","buildCollectionHref","Link"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceDisplay } from \"./price-display.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base group relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1 space-y-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n {listingOrder && (\n <div className=\"flex justify-end\">\n <PriceDisplay\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n scale=\"card\"\n />\n </div>\n )}\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"px-2.5\", hasPrimaryAction ? \"shrink-0\" : \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n View\n </Link>\n\n {isOwner ? (\n !listingOrder ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n Sell\n </button>\n ) : null\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : null}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n Sell\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["buildAssetHref","buildCollectionHref","Link"]}
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
import { cn } from "../utils/cn.js";
|
|
26
26
|
import { formatDisplayPrice } from "../utils/format.js";
|
|
27
27
|
import { CurrencyIcon } from "./currency-icon.js";
|
|
28
|
-
import {
|
|
28
|
+
import { PriceDisplay } from "./price-display.js";
|
|
29
29
|
import { IpTypeBadge } from "./ip-type-badge.js";
|
|
30
30
|
import { AnimatedTokenMedia } from "./animated-token-media.js";
|
|
31
31
|
import { isLivingRenderCollection } from "../data/living-render-collections.js";
|
|
@@ -94,13 +94,13 @@ function TokenCard({
|
|
|
94
94
|
] }),
|
|
95
95
|
/* @__PURE__ */ jsxs("div", { className: "px-3 pt-2.5 pb-4 flex-1 space-y-1", children: [
|
|
96
96
|
/* @__PURE__ */ jsx("p", { className: "text-base font-bold line-clamp-2 leading-snug", children: name }),
|
|
97
|
-
listingOrder && /* @__PURE__ */ jsx("
|
|
98
|
-
|
|
97
|
+
listingOrder && /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
|
|
98
|
+
PriceDisplay,
|
|
99
99
|
{
|
|
100
100
|
amountFormatted: listingOrder.price.formatted,
|
|
101
101
|
currency: listingOrder.price.currency,
|
|
102
102
|
usdValue,
|
|
103
|
-
|
|
103
|
+
scale: "card"
|
|
104
104
|
}
|
|
105
105
|
) })
|
|
106
106
|
] })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceChipContent } from \"./dual-price.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base group relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1 space-y-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n {listingOrder && (\n <p className=\"flex items-center justify-end gap-1.5 text-sm tabular-nums\">\n <PriceChipContent\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n tone=\"card\"\n />\n </p>\n )}\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"px-2.5\", hasPrimaryAction ? \"shrink-0\" : \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n View\n </Link>\n\n {isOwner ? (\n !listingOrder ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n Sell\n </button>\n ) : null\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : null}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n Sell\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/token-card.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport {\n Loader2, ArrowUpRight, MoreHorizontal, Zap, HandCoins, Tag,\n Layers, GitBranch, Flag, UserCircle2, ArrowRightLeft, XCircle,\n} from \"lucide-react\";\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuItem,\n DropdownMenuSeparator, DropdownMenuTrigger,\n} from \"./dropdown-menu.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { formatDisplayPrice } from \"../utils/format.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { PriceDisplay } from \"./price-display.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AnimatedTokenMedia } from \"./animated-token-media.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { assetHref as buildAssetHref, collectionHref as buildCollectionHref } from \"@medialane/sdk\";\nimport type { ApiToken, Chain } from \"@medialane/sdk\";\nimport { tokenProfileLink } from \"../utils/token-profile-link.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\n\nconst BTN_BASE = \"h-8 rounded-[9px] flex items-center justify-center gap-1.5 text-xs font-semibold transition-all active:scale-[0.98] shadow-none border-0\";\nconst BTN_OUTLINE = cn(BTN_BASE, \"border border-border/60 text-foreground hover:bg-muted/60\");\n\nexport interface TokenCardProps {\n token: ApiToken;\n isOwner?: boolean;\n onList?: (token: ApiToken) => void;\n onTransfer?: (token: ApiToken) => void;\n onCancel?: (token: ApiToken) => void;\n onBuy?: (token: ApiToken) => void;\n onOffer?: (token: ApiToken) => void;\n onReport?: (token: ApiToken) => void;\n\n usdValue?: string | null;\n}\n\nexport function TokenCard({\n token,\n isOwner = false,\n onList,\n onTransfer,\n onCancel,\n onBuy,\n onOffer,\n onReport,\n usdValue,\n}: TokenCardProps) {\n const resolveImage = useImageUrl();\n const name = token.metadata?.name || `Token #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image, { width: 480 });\n const animationUrl = token.metadata?.animationUrl ?? null;\n const ipType = token.metadata?.ipType;\n\n const listingOrder = token.activeOrders?.find(\n (o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\"\n );\n\n const profileLink = tokenProfileLink(token);\n const hasPrimaryAction = isOwner ? !listingOrder : listingOrder ? !!onBuy : !!onOffer;\n\n const chain = token.chain.toUpperCase() as Chain;\n const live = isLivingRenderCollection(chain, token.contractAddress);\n const assetHref = buildAssetHref(chain, token.contractAddress, token.tokenId);\n const collectionHref = buildCollectionHref(chain, token.contractAddress);\n const remixHref = `/create/remix/${token.contractAddress}/${token.tokenId}`;\n\n const handleBuy = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onBuy?.(token);\n };\n\n const handleOffer = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onOffer?.(token);\n };\n\n return (\n <div className=\"card-base group relative overflow-hidden flex flex-col w-full\">\n {ipType && (\n <div className=\"absolute top-2 right-2 z-10\">\n <IpTypeBadge ipType={ipType as any} size=\"sm\" />\n </div>\n )}\n\n <Link href={assetHref} className=\"flex flex-col flex-1\">\n\n <div className=\"relative aspect-square bg-muted overflow-hidden shrink-0\">\n <AnimatedTokenMedia\n image={image}\n animationUrl={animationUrl}\n live={live}\n alt={name}\n mode=\"fill\"\n sizes=\"(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 22vw\"\n className=\"object-cover\"\n fallback={\n <div className=\"absolute inset-0 bg-gradient-to-br from-brand-purple/15 to-brand-blue/15\" />\n }\n />\n\n {(token.metadataStatus === \"PENDING\" || token.metadataStatus === \"FETCHING\") && (\n <div className=\"absolute bottom-0 inset-x-0 flex items-center justify-center gap-1.5 bg-black/50 backdrop-blur-sm py-1.5\">\n <Loader2 className=\"h-3 w-3 animate-spin text-white/70\" />\n <span className=\"text-2xs text-white/70\">Indexing…</span>\n </div>\n )}\n </div>\n\n <div className=\"px-3 pt-2.5 pb-4 flex-1 space-y-1\">\n <p className=\"text-base font-bold line-clamp-2 leading-snug\">{name}</p>\n {listingOrder && (\n <div className=\"flex justify-end\">\n <PriceDisplay\n amountFormatted={listingOrder.price.formatted}\n currency={listingOrder.price.currency}\n usdValue={usdValue}\n scale=\"card\"\n />\n </div>\n )}\n </div>\n </Link>\n\n <div className=\"px-3 pb-3 flex items-center gap-1.5\">\n\n <Link href={assetHref} className={cn(BTN_OUTLINE, \"px-2.5\", hasPrimaryAction ? \"shrink-0\" : \"flex-1\")}>\n <ArrowUpRight className=\"h-3.5 w-3.5\" />\n View\n </Link>\n\n {isOwner ? (\n !listingOrder ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-purple border-brand-purple/30 hover:bg-brand-purple/10 hover:text-brand-purple\")}\n onClick={(e) => { e.preventDefault(); e.stopPropagation(); onList?.(token); }}\n >\n <Tag className=\"h-3.5 w-3.5 mr-1.5\" />\n Sell\n </button>\n ) : null\n ) : listingOrder && onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-8\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" />\n Buy\n </button>\n </div>\n ) : !listingOrder && onOffer ? (\n <button\n className={cn(BTN_OUTLINE, \"flex-1 text-brand-orange border-brand-orange/30 hover:bg-brand-orange/10 hover:text-brand-orange\")}\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5 mr-1.5\" />\n Offer\n </button>\n ) : null}\n\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n className={cn(BTN_OUTLINE, \"w-8 p-0 shrink-0\")}\n aria-label=\"More actions\"\n >\n <MoreHorizontal className=\"h-3.5 w-3.5\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n\n <DropdownMenuItem asChild>\n <Link href={assetHref} className=\"flex items-center gap-2\">\n <ArrowUpRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View asset\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n {isOwner ? (\n <>\n {!listingOrder && onList && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\"\n onClick={() => onList(token)}\n >\n <Tag className=\"h-3.5 w-3.5\" />\n Sell\n </DropdownMenuItem>\n )}\n {onTransfer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2\"\n onClick={() => onTransfer(token)}\n >\n <ArrowRightLeft className=\"h-3.5 w-3.5 text-muted-foreground\" />\n Transfer\n </DropdownMenuItem>\n )}\n {listingOrder && onCancel && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={() => onCancel(token)}\n >\n <XCircle className=\"h-3.5 w-3.5\" />\n Cancel listing\n </DropdownMenuItem>\n )}\n </>\n ) : (\n <>\n {listingOrder && onBuy && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-blue focus:text-brand-blue\"\n onClick={handleBuy}\n >\n <Zap className=\"h-3.5 w-3.5\" />\n <span className=\"flex items-center gap-1\">\n Buy —\n <CurrencyIcon symbol={listingOrder.price.currency} size={12} />\n {formatDisplayPrice(listingOrder.price.formatted)}\n </span>\n </DropdownMenuItem>\n )}\n {onOffer && (\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-brand-orange focus:text-brand-orange\"\n onClick={handleOffer}\n >\n <HandCoins className=\"h-3.5 w-3.5\" />\n Make offer\n </DropdownMenuItem>\n )}\n </>\n )}\n\n <DropdownMenuItem asChild>\n <Link href={remixHref} className=\"flex items-center gap-2 text-brand-purple focus:text-brand-purple\">\n <GitBranch className=\"h-3.5 w-3.5\" />\n Remix\n </Link>\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem asChild>\n <Link href={collectionHref} className=\"flex items-center gap-2\">\n <Layers className=\"h-3.5 w-3.5 text-muted-foreground\" />\n View collection\n </Link>\n </DropdownMenuItem>\n\n {profileLink && (\n <DropdownMenuItem asChild>\n <Link href={profileLink.href} className=\"flex items-center gap-2\">\n <UserCircle2 className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {profileLink.label}\n </Link>\n </DropdownMenuItem>\n )}\n\n {onReport && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"flex items-center gap-2 text-muted-foreground focus:text-muted-foreground\"\n onClick={() => onReport(token)}\n >\n <Flag className=\"h-3.5 w-3.5\" />\n Report\n </DropdownMenuItem>\n </>\n )}\n\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </div>\n );\n}\n\nexport function TokenCardSkeleton() {\n return (\n <div className=\"card-base overflow-hidden\">\n <div className=\"aspect-square w-full animate-pulse bg-muted\" />\n <div className=\"px-3 pt-2.5 pb-3 space-y-1.5\">\n <div className=\"h-4 w-3/4 rounded-md animate-pulse bg-muted\" />\n </div>\n <div className=\"px-3 pb-3 flex gap-1.5\">\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n <div className=\"h-8 flex-1 rounded-[9px] animate-pulse bg-muted\" />\n <div className=\"h-8 w-8 rounded-[9px] animate-pulse bg-muted shrink-0\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/utils/format.cjs
CHANGED
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var format_exports = {};
|
|
20
20
|
__export(format_exports, {
|
|
21
|
+
formatCompactPrice: () => formatCompactPrice,
|
|
21
22
|
formatDisplayPrice: () => formatDisplayPrice,
|
|
22
23
|
formatSmallDecimal: () => formatSmallDecimal,
|
|
23
24
|
formatUsd: () => formatUsd,
|
|
@@ -75,6 +76,13 @@ function formatDisplayPrice(price) {
|
|
|
75
76
|
});
|
|
76
77
|
return currencyPart ? `${formatted} ${currencyPart}` : formatted;
|
|
77
78
|
}
|
|
79
|
+
const COMPACT_FORMAT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
|
|
80
|
+
function formatCompactPrice(price) {
|
|
81
|
+
if (price === null || price === void 0) return "";
|
|
82
|
+
const num = Number(String(price).split(" ")[0]);
|
|
83
|
+
if (!isFinite(num) || Math.abs(num) < 1e3) return formatDisplayPrice(price);
|
|
84
|
+
return COMPACT_FORMAT.format(num);
|
|
85
|
+
}
|
|
78
86
|
function parsePriceDisplay(raw) {
|
|
79
87
|
if (!raw) return { numStr: "\u2014", symbol: null };
|
|
80
88
|
const parts = raw.trim().split(" ");
|
|
@@ -90,6 +98,7 @@ function parsePriceDisplay(raw) {
|
|
|
90
98
|
}
|
|
91
99
|
// Annotate the CommonJS export names for ESM import in node:
|
|
92
100
|
0 && (module.exports = {
|
|
101
|
+
formatCompactPrice,
|
|
93
102
|
formatDisplayPrice,
|
|
94
103
|
formatSmallDecimal,
|
|
95
104
|
formatUsd,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/format.ts"],"sourcesContent":["\nexport function isStableCurrency(symbol: string | null | undefined): boolean {\n return symbol === \"USDC\" || symbol === \"USDT\";\n}\n\nexport function formatUsd(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n if (n > 0 && n < 0.01) return \"<$0.01\";\n return `$${n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\n}\n\nconst SUBSCRIPTS = \"₀₁₂₃₄₅₆₇₈₉\";\n\nconst toSubscript = (n: number) =>\n String(n)\n .split(\"\")\n .map((d) => SUBSCRIPTS[Number(d)])\n .join(\"\");\n\nexport function formatSmallDecimal(n: number, significantDigits = 3): string {\n if (!isFinite(n) || n === 0) return \"0\";\n const abs = Math.abs(n);\n const sign = n < 0 ? \"-\" : \"\";\n\n if (abs >= 1) return sign + abs.toLocaleString(undefined, { maximumFractionDigits: 4 });\n if (abs >= 0.0001) return sign + abs.toPrecision(significantDigits).replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n\n const zeros = -Math.floor(Math.log10(abs)) - 1;\n const digits = abs\n .toExponential(significantDigits - 1)\n .replace(/e[+-]\\d+$/, \"\")\n .replace(\".\", \"\")\n .replace(/0+$/, \"\");\n\n return `${sign}0.0${toSubscript(zeros)}${digits || \"0\"}`;\n}\n\nexport function formatUsdPrice(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n return `$${formatSmallDecimal(n)}`;\n}\n\nfunction adaptiveDecimals(num: number): number {\n if (num === 0 || num >= 1) return 2;\n if (num >= 0.01) return 4;\n const leadingZeros = Math.floor(-Math.log10(Math.abs(num)));\n return leadingZeros + 2;\n}\n\nexport function formatDisplayPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const priceStr = String(price);\n const parts = priceStr.split(\" \");\n const numericPart = parts[0];\n const currencyPart = parts.length > 1 ? parts.slice(1).join(\" \") : \"\";\n const num = Number(numericPart);\n if (isNaN(num)) return priceStr;\n\n if (num !== 0 && Math.abs(num) < 0.0001) {\n const compressed = formatSmallDecimal(num);\n return currencyPart ? `${compressed} ${currencyPart}` : compressed;\n }\n\n const maxDecimals = adaptiveDecimals(num);\n const formatted = num.toLocaleString(undefined, {\n minimumFractionDigits: Math.min(2, maxDecimals),\n maximumFractionDigits: maxDecimals,\n });\n return currencyPart ? `${formatted} ${currencyPart}` : formatted;\n}\n\nexport function parsePriceDisplay(raw: string | null | undefined): { numStr: string; symbol: string | null } {\n if (!raw) return { numStr: \"—\", symbol: null };\n const parts = raw.trim().split(\" \");\n const sym = parts.length > 1 ? parts[parts.length - 1] : null;\n const numericPart = sym ? parts.slice(0, -1).join(\" \") : raw;\n const num = Number(numericPart);\n if (isNaN(num)) return { numStr: \"—\", symbol: sym };\n if (num > 1e12) return { numStr: \"—\", symbol: null };\n const formatted = formatDisplayPrice(numericPart);\n if (!formatted || formatted === \"—\") return { numStr: \"—\", symbol: sym };\n const clean = formatted.replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n return { numStr: clean || \"—\", symbol: sym };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/format.ts"],"sourcesContent":["\nexport function isStableCurrency(symbol: string | null | undefined): boolean {\n return symbol === \"USDC\" || symbol === \"USDT\";\n}\n\nexport function formatUsd(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n if (n > 0 && n < 0.01) return \"<$0.01\";\n return `$${n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\n}\n\nconst SUBSCRIPTS = \"₀₁₂₃₄₅₆₇₈₉\";\n\nconst toSubscript = (n: number) =>\n String(n)\n .split(\"\")\n .map((d) => SUBSCRIPTS[Number(d)])\n .join(\"\");\n\nexport function formatSmallDecimal(n: number, significantDigits = 3): string {\n if (!isFinite(n) || n === 0) return \"0\";\n const abs = Math.abs(n);\n const sign = n < 0 ? \"-\" : \"\";\n\n if (abs >= 1) return sign + abs.toLocaleString(undefined, { maximumFractionDigits: 4 });\n if (abs >= 0.0001) return sign + abs.toPrecision(significantDigits).replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n\n const zeros = -Math.floor(Math.log10(abs)) - 1;\n const digits = abs\n .toExponential(significantDigits - 1)\n .replace(/e[+-]\\d+$/, \"\")\n .replace(\".\", \"\")\n .replace(/0+$/, \"\");\n\n return `${sign}0.0${toSubscript(zeros)}${digits || \"0\"}`;\n}\n\nexport function formatUsdPrice(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n return `$${formatSmallDecimal(n)}`;\n}\n\nfunction adaptiveDecimals(num: number): number {\n if (num === 0 || num >= 1) return 2;\n if (num >= 0.01) return 4;\n const leadingZeros = Math.floor(-Math.log10(Math.abs(num)));\n return leadingZeros + 2;\n}\n\nexport function formatDisplayPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const priceStr = String(price);\n const parts = priceStr.split(\" \");\n const numericPart = parts[0];\n const currencyPart = parts.length > 1 ? parts.slice(1).join(\" \") : \"\";\n const num = Number(numericPart);\n if (isNaN(num)) return priceStr;\n\n if (num !== 0 && Math.abs(num) < 0.0001) {\n const compressed = formatSmallDecimal(num);\n return currencyPart ? `${compressed} ${currencyPart}` : compressed;\n }\n\n const maxDecimals = adaptiveDecimals(num);\n const formatted = num.toLocaleString(undefined, {\n minimumFractionDigits: Math.min(2, maxDecimals),\n maximumFractionDigits: maxDecimals,\n });\n return currencyPart ? `${formatted} ${currencyPart}` : formatted;\n}\n\nconst COMPACT_FORMAT = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\n\nexport function formatCompactPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const num = Number(String(price).split(\" \")[0]);\n if (!isFinite(num) || Math.abs(num) < 1000) return formatDisplayPrice(price);\n return COMPACT_FORMAT.format(num);\n}\n\nexport function parsePriceDisplay(raw: string | null | undefined): { numStr: string; symbol: string | null } {\n if (!raw) return { numStr: \"—\", symbol: null };\n const parts = raw.trim().split(\" \");\n const sym = parts.length > 1 ? parts[parts.length - 1] : null;\n const numericPart = sym ? parts.slice(0, -1).join(\" \") : raw;\n const num = Number(numericPart);\n if (isNaN(num)) return { numStr: \"—\", symbol: sym };\n if (num > 1e12) return { numStr: \"—\", symbol: null };\n const formatted = formatDisplayPrice(numericPart);\n if (!formatted || formatted === \"—\") return { numStr: \"—\", symbol: sym };\n const clean = formatted.replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n return { numStr: clean || \"—\", symbol: sym };\n}\n"],"mappings":"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","names":[]}
|
package/dist/utils/format.d.cts
CHANGED
|
@@ -3,9 +3,10 @@ declare function formatUsd(n: number | null | undefined): string | null;
|
|
|
3
3
|
declare function formatSmallDecimal(n: number, significantDigits?: number): string;
|
|
4
4
|
declare function formatUsdPrice(n: number | null | undefined): string | null;
|
|
5
5
|
declare function formatDisplayPrice(price: string | number | null | undefined): string;
|
|
6
|
+
declare function formatCompactPrice(price: string | number | null | undefined): string;
|
|
6
7
|
declare function parsePriceDisplay(raw: string | null | undefined): {
|
|
7
8
|
numStr: string;
|
|
8
9
|
symbol: string | null;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
export { formatDisplayPrice, formatSmallDecimal, formatUsd, formatUsdPrice, isStableCurrency, parsePriceDisplay };
|
|
12
|
+
export { formatCompactPrice, formatDisplayPrice, formatSmallDecimal, formatUsd, formatUsdPrice, isStableCurrency, parsePriceDisplay };
|
package/dist/utils/format.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ declare function formatUsd(n: number | null | undefined): string | null;
|
|
|
3
3
|
declare function formatSmallDecimal(n: number, significantDigits?: number): string;
|
|
4
4
|
declare function formatUsdPrice(n: number | null | undefined): string | null;
|
|
5
5
|
declare function formatDisplayPrice(price: string | number | null | undefined): string;
|
|
6
|
+
declare function formatCompactPrice(price: string | number | null | undefined): string;
|
|
6
7
|
declare function parsePriceDisplay(raw: string | null | undefined): {
|
|
7
8
|
numStr: string;
|
|
8
9
|
symbol: string | null;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
export { formatDisplayPrice, formatSmallDecimal, formatUsd, formatUsdPrice, isStableCurrency, parsePriceDisplay };
|
|
12
|
+
export { formatCompactPrice, formatDisplayPrice, formatSmallDecimal, formatUsd, formatUsdPrice, isStableCurrency, parsePriceDisplay };
|
package/dist/utils/format.js
CHANGED
|
@@ -47,6 +47,13 @@ function formatDisplayPrice(price) {
|
|
|
47
47
|
});
|
|
48
48
|
return currencyPart ? `${formatted} ${currencyPart}` : formatted;
|
|
49
49
|
}
|
|
50
|
+
const COMPACT_FORMAT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
|
|
51
|
+
function formatCompactPrice(price) {
|
|
52
|
+
if (price === null || price === void 0) return "";
|
|
53
|
+
const num = Number(String(price).split(" ")[0]);
|
|
54
|
+
if (!isFinite(num) || Math.abs(num) < 1e3) return formatDisplayPrice(price);
|
|
55
|
+
return COMPACT_FORMAT.format(num);
|
|
56
|
+
}
|
|
50
57
|
function parsePriceDisplay(raw) {
|
|
51
58
|
if (!raw) return { numStr: "\u2014", symbol: null };
|
|
52
59
|
const parts = raw.trim().split(" ");
|
|
@@ -61,6 +68,7 @@ function parsePriceDisplay(raw) {
|
|
|
61
68
|
return { numStr: clean || "\u2014", symbol: sym };
|
|
62
69
|
}
|
|
63
70
|
export {
|
|
71
|
+
formatCompactPrice,
|
|
64
72
|
formatDisplayPrice,
|
|
65
73
|
formatSmallDecimal,
|
|
66
74
|
formatUsd,
|
package/dist/utils/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/format.ts"],"sourcesContent":["\nexport function isStableCurrency(symbol: string | null | undefined): boolean {\n return symbol === \"USDC\" || symbol === \"USDT\";\n}\n\nexport function formatUsd(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n if (n > 0 && n < 0.01) return \"<$0.01\";\n return `$${n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\n}\n\nconst SUBSCRIPTS = \"₀₁₂₃₄₅₆₇₈₉\";\n\nconst toSubscript = (n: number) =>\n String(n)\n .split(\"\")\n .map((d) => SUBSCRIPTS[Number(d)])\n .join(\"\");\n\nexport function formatSmallDecimal(n: number, significantDigits = 3): string {\n if (!isFinite(n) || n === 0) return \"0\";\n const abs = Math.abs(n);\n const sign = n < 0 ? \"-\" : \"\";\n\n if (abs >= 1) return sign + abs.toLocaleString(undefined, { maximumFractionDigits: 4 });\n if (abs >= 0.0001) return sign + abs.toPrecision(significantDigits).replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n\n const zeros = -Math.floor(Math.log10(abs)) - 1;\n const digits = abs\n .toExponential(significantDigits - 1)\n .replace(/e[+-]\\d+$/, \"\")\n .replace(\".\", \"\")\n .replace(/0+$/, \"\");\n\n return `${sign}0.0${toSubscript(zeros)}${digits || \"0\"}`;\n}\n\nexport function formatUsdPrice(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n return `$${formatSmallDecimal(n)}`;\n}\n\nfunction adaptiveDecimals(num: number): number {\n if (num === 0 || num >= 1) return 2;\n if (num >= 0.01) return 4;\n const leadingZeros = Math.floor(-Math.log10(Math.abs(num)));\n return leadingZeros + 2;\n}\n\nexport function formatDisplayPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const priceStr = String(price);\n const parts = priceStr.split(\" \");\n const numericPart = parts[0];\n const currencyPart = parts.length > 1 ? parts.slice(1).join(\" \") : \"\";\n const num = Number(numericPart);\n if (isNaN(num)) return priceStr;\n\n if (num !== 0 && Math.abs(num) < 0.0001) {\n const compressed = formatSmallDecimal(num);\n return currencyPart ? `${compressed} ${currencyPart}` : compressed;\n }\n\n const maxDecimals = adaptiveDecimals(num);\n const formatted = num.toLocaleString(undefined, {\n minimumFractionDigits: Math.min(2, maxDecimals),\n maximumFractionDigits: maxDecimals,\n });\n return currencyPart ? `${formatted} ${currencyPart}` : formatted;\n}\n\nexport function parsePriceDisplay(raw: string | null | undefined): { numStr: string; symbol: string | null } {\n if (!raw) return { numStr: \"—\", symbol: null };\n const parts = raw.trim().split(\" \");\n const sym = parts.length > 1 ? parts[parts.length - 1] : null;\n const numericPart = sym ? parts.slice(0, -1).join(\" \") : raw;\n const num = Number(numericPart);\n if (isNaN(num)) return { numStr: \"—\", symbol: sym };\n if (num > 1e12) return { numStr: \"—\", symbol: null };\n const formatted = formatDisplayPrice(numericPart);\n if (!formatted || formatted === \"—\") return { numStr: \"—\", symbol: sym };\n const clean = formatted.replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n return { numStr: clean || \"—\", symbol: sym };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/format.ts"],"sourcesContent":["\nexport function isStableCurrency(symbol: string | null | undefined): boolean {\n return symbol === \"USDC\" || symbol === \"USDT\";\n}\n\nexport function formatUsd(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n if (n > 0 && n < 0.01) return \"<$0.01\";\n return `$${n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\n}\n\nconst SUBSCRIPTS = \"₀₁₂₃₄₅₆₇₈₉\";\n\nconst toSubscript = (n: number) =>\n String(n)\n .split(\"\")\n .map((d) => SUBSCRIPTS[Number(d)])\n .join(\"\");\n\nexport function formatSmallDecimal(n: number, significantDigits = 3): string {\n if (!isFinite(n) || n === 0) return \"0\";\n const abs = Math.abs(n);\n const sign = n < 0 ? \"-\" : \"\";\n\n if (abs >= 1) return sign + abs.toLocaleString(undefined, { maximumFractionDigits: 4 });\n if (abs >= 0.0001) return sign + abs.toPrecision(significantDigits).replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n\n const zeros = -Math.floor(Math.log10(abs)) - 1;\n const digits = abs\n .toExponential(significantDigits - 1)\n .replace(/e[+-]\\d+$/, \"\")\n .replace(\".\", \"\")\n .replace(/0+$/, \"\");\n\n return `${sign}0.0${toSubscript(zeros)}${digits || \"0\"}`;\n}\n\nexport function formatUsdPrice(n: number | null | undefined): string | null {\n if (n == null || !isFinite(n)) return null;\n return `$${formatSmallDecimal(n)}`;\n}\n\nfunction adaptiveDecimals(num: number): number {\n if (num === 0 || num >= 1) return 2;\n if (num >= 0.01) return 4;\n const leadingZeros = Math.floor(-Math.log10(Math.abs(num)));\n return leadingZeros + 2;\n}\n\nexport function formatDisplayPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const priceStr = String(price);\n const parts = priceStr.split(\" \");\n const numericPart = parts[0];\n const currencyPart = parts.length > 1 ? parts.slice(1).join(\" \") : \"\";\n const num = Number(numericPart);\n if (isNaN(num)) return priceStr;\n\n if (num !== 0 && Math.abs(num) < 0.0001) {\n const compressed = formatSmallDecimal(num);\n return currencyPart ? `${compressed} ${currencyPart}` : compressed;\n }\n\n const maxDecimals = adaptiveDecimals(num);\n const formatted = num.toLocaleString(undefined, {\n minimumFractionDigits: Math.min(2, maxDecimals),\n maximumFractionDigits: maxDecimals,\n });\n return currencyPart ? `${formatted} ${currencyPart}` : formatted;\n}\n\nconst COMPACT_FORMAT = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\n\nexport function formatCompactPrice(price: string | number | null | undefined): string {\n if (price === null || price === undefined) return \"\";\n const num = Number(String(price).split(\" \")[0]);\n if (!isFinite(num) || Math.abs(num) < 1000) return formatDisplayPrice(price);\n return COMPACT_FORMAT.format(num);\n}\n\nexport function parsePriceDisplay(raw: string | null | undefined): { numStr: string; symbol: string | null } {\n if (!raw) return { numStr: \"—\", symbol: null };\n const parts = raw.trim().split(\" \");\n const sym = parts.length > 1 ? parts[parts.length - 1] : null;\n const numericPart = sym ? parts.slice(0, -1).join(\" \") : raw;\n const num = Number(numericPart);\n if (isNaN(num)) return { numStr: \"—\", symbol: sym };\n if (num > 1e12) return { numStr: \"—\", symbol: null };\n const formatted = formatDisplayPrice(numericPart);\n if (!formatted || formatted === \"—\") return { numStr: \"—\", symbol: sym };\n const clean = formatted.replace(/(\\.\\d*?)0+$/, \"$1\").replace(/\\.$/, \"\");\n return { numStr: clean || \"—\", symbol: sym };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -7,7 +7,7 @@ declare function useTokenBalance(symbol: string | null, holderAddress: string |
|
|
|
7
7
|
rawBalance: bigint | null;
|
|
8
8
|
isLoading: boolean;
|
|
9
9
|
error: any;
|
|
10
|
-
decimals:
|
|
10
|
+
decimals: 8 | 6 | 18;
|
|
11
11
|
};
|
|
12
12
|
declare function hasSufficientBalance(rawBalance: bigint | null, requiredHuman: string, decimals: number): boolean | null;
|
|
13
13
|
|
|
@@ -7,7 +7,7 @@ declare function useTokenBalance(symbol: string | null, holderAddress: string |
|
|
|
7
7
|
rawBalance: bigint | null;
|
|
8
8
|
isLoading: boolean;
|
|
9
9
|
error: any;
|
|
10
|
-
decimals:
|
|
10
|
+
decimals: 8 | 6 | 18;
|
|
11
11
|
};
|
|
12
12
|
declare function hasSufficientBalance(rawBalance: bigint | null, requiredHuman: string, decimals: number): boolean | null;
|
|
13
13
|
|