@medialane/ui 0.114.0 → 0.116.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/asset-card.cjs +10 -17
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.js +11 -18
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/asset-marketplace-panel.cjs +3 -35
- package/dist/components/asset-marketplace-panel.cjs.map +1 -1
- package/dist/components/asset-marketplace-panel.js +4 -36
- package/dist/components/asset-marketplace-panel.js.map +1 -1
- package/dist/components/dual-price.cjs +118 -0
- package/dist/components/dual-price.cjs.map +1 -0
- package/dist/components/dual-price.d.cts +77 -0
- package/dist/components/dual-price.d.ts +77 -0
- package/dist/components/dual-price.js +92 -0
- package/dist/components/dual-price.js.map +1 -0
- package/dist/components/listing-card.cjs +2 -35
- package/dist/components/listing-card.cjs.map +1 -1
- package/dist/components/listing-card.js +2 -35
- package/dist/components/listing-card.js.map +1 -1
- package/dist/components/token-card.cjs +12 -6
- package/dist/components/token-card.cjs.map +1 -1
- package/dist/components/token-card.d.cts +8 -1
- package/dist/components/token-card.d.ts +8 -1
- package/dist/components/token-card.js +12 -6
- package/dist/components/token-card.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var dual_price_exports = {};
|
|
21
|
+
__export(dual_price_exports, {
|
|
22
|
+
CoinChip: () => CoinChip,
|
|
23
|
+
DualPrice: () => DualPrice,
|
|
24
|
+
PriceChipContent: () => PriceChipContent
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(dual_price_exports);
|
|
27
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
28
|
+
var import_currency_icon = require("./currency-icon.js");
|
|
29
|
+
var import_format = require("../utils/format.js");
|
|
30
|
+
function CoinChip({ symbol, size }) {
|
|
31
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
32
|
+
"span",
|
|
33
|
+
{
|
|
34
|
+
className: "grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]",
|
|
35
|
+
style: { width: size + 10, height: size + 10 },
|
|
36
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: symbol ?? "", size })
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
const DISPLAY_FACE = "font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums";
|
|
41
|
+
const DUAL_PRICE_SCALES = {
|
|
42
|
+
/** Full-width hero contexts: AssetMarketplacePanel's main price. Has room
|
|
43
|
+
* to spell out the currency ("0.07 ETH"), not just imply it via icon. */
|
|
44
|
+
hero: { fiat: "text-4xl", crypto: "text-2xl", chip: 16, stableChip: 13, divider: "h-7", showCurrencyLabel: true },
|
|
45
|
+
/** Card contexts: ListingCard's full variant — denser, the coin icon
|
|
46
|
+
* already conveys the currency, a text label would be redundant. */
|
|
47
|
+
card: { fiat: "text-lg", crypto: "text-sm", chip: 11, stableChip: 9, divider: "h-4", showCurrencyLabel: false }
|
|
48
|
+
};
|
|
49
|
+
function DualPrice({
|
|
50
|
+
amountFormatted,
|
|
51
|
+
currency,
|
|
52
|
+
usdValue,
|
|
53
|
+
scale,
|
|
54
|
+
trailing
|
|
55
|
+
}) {
|
|
56
|
+
if (!amountFormatted) return null;
|
|
57
|
+
const s = DUAL_PRICE_SCALES[scale];
|
|
58
|
+
const cryptoDisplay = (0, import_format.formatDisplayPrice)(amountFormatted);
|
|
59
|
+
if (!usdValue) {
|
|
60
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `flex items-center gap-2.5 ${DISPLAY_FACE} ${s.fiat}`, children: [
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: s.chip }),
|
|
62
|
+
cryptoDisplay,
|
|
63
|
+
trailing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-0.5", children: trailing })
|
|
64
|
+
] });
|
|
65
|
+
}
|
|
66
|
+
const stable = (0, import_format.isStableCurrency)(currency);
|
|
67
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${DISPLAY_FACE} ${s.fiat}`, children: usdValue }),
|
|
69
|
+
!stable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${s.divider} w-px bg-border/60 shrink-0` }),
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: stable ? s.stableChip : s.chip }),
|
|
72
|
+
stable ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold text-muted-foreground", children: currency }) : s.showCurrencyLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-baseline gap-1.5", children: [
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${DISPLAY_FACE} ${s.crypto} text-foreground/90`, children: cryptoDisplay }),
|
|
74
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold text-muted-foreground/70", children: currency })
|
|
75
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${DISPLAY_FACE} ${s.crypto} text-foreground/90`, children: cryptoDisplay })
|
|
76
|
+
] }),
|
|
77
|
+
trailing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-0.5", children: trailing })
|
|
78
|
+
] });
|
|
79
|
+
}
|
|
80
|
+
const CHIP_TONES = {
|
|
81
|
+
/** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed
|
|
82
|
+
* readable regardless of the artwork or the viewer's theme. */
|
|
83
|
+
"overlay-dark": { dot: "text-white/30", text: "text-white/65" },
|
|
84
|
+
/** Theme-aware card backgrounds (TokenCard). */
|
|
85
|
+
card: { dot: "text-muted-foreground/50", text: "text-muted-foreground" }
|
|
86
|
+
};
|
|
87
|
+
function PriceChipContent({
|
|
88
|
+
amountFormatted,
|
|
89
|
+
currency,
|
|
90
|
+
usdValue,
|
|
91
|
+
tone
|
|
92
|
+
}) {
|
|
93
|
+
if (!amountFormatted) return null;
|
|
94
|
+
const cryptoDisplay = (0, import_format.formatDisplayPrice)(amountFormatted);
|
|
95
|
+
const stable = (0, import_format.isStableCurrency)(currency);
|
|
96
|
+
if (!usdValue) {
|
|
97
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
98
|
+
currency && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: currency, size: 13 }),
|
|
99
|
+
cryptoDisplay
|
|
100
|
+
] });
|
|
101
|
+
}
|
|
102
|
+
const t = CHIP_TONES[tone];
|
|
103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
104
|
+
usdValue,
|
|
105
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: t.dot, children: "\xB7" }),
|
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: `inline-flex items-center gap-1 font-semibold ${t.text}`, children: [
|
|
107
|
+
currency && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: currency, size: 12 }),
|
|
108
|
+
stable ? currency : cryptoDisplay
|
|
109
|
+
] })
|
|
110
|
+
] });
|
|
111
|
+
}
|
|
112
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
113
|
+
0 && (module.exports = {
|
|
114
|
+
CoinChip,
|
|
115
|
+
DualPrice,
|
|
116
|
+
PriceChipContent
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=dual-price.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\n/** Currency icon in the soft circular chip used throughout the wallet UI —\n * reads as a coin, not a stray glyph floating next to text. */\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nconst DISPLAY_FACE = \"font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n /** Full-width hero contexts: AssetMarketplacePanel's main price. Has room\n * to spell out the currency (\"0.07 ETH\"), not just imply it via icon. */\n hero: { fiat: \"text-4xl\", crypto: \"text-2xl\", chip: 16, stableChip: 13, divider: \"h-7\", showCurrencyLabel: true },\n /** Card contexts: ListingCard's full variant — denser, the coin icon\n * already conveys the currency, a text label would be redundant. */\n card: { fiat: \"text-lg\", crypto: \"text-sm\", chip: 11, stableChip: 9, divider: \"h-4\", showCurrencyLabel: false },\n} as const;\n\n/**\n * Equal-weight dual price: fiat and the on-chain currency shown as peers,\n * not primary/afterthought — this platform's audience spans non-crypto\n * newcomers who read fiat and crypto-native buyers who read the token\n * amount. Both use the brand display face at a real step-down in scale so\n * the pairing reads as \"two related numbers,\" not one dominant + one\n * caption. Falls back to crypto-only when no USD rate is available. When\n * the currency is itself a USD-pegged stablecoin, the crypto amount\n * collapses to a small currency badge — showing \"$12.00\" beside \"12.00\n * USDC\" would just be the same number twice.\n */\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n\n if (!usdValue) {\n return (\n <div className={`flex items-center gap-2.5 ${DISPLAY_FACE} ${s.fiat}`}>\n <CoinChip symbol={currency} size={s.chip} />\n {cryptoDisplay}\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <span className={`${DISPLAY_FACE} ${s.fiat}`}>{usdValue}</span>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={stable ? s.stableChip : s.chip} />\n {stable ? (\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n ) : s.showCurrencyLabel ? (\n <span className=\"flex items-baseline gap-1.5\">\n <span className={`${DISPLAY_FACE} ${s.crypto} text-foreground/90`}>{cryptoDisplay}</span>\n <span className=\"text-sm font-semibold text-muted-foreground/70\">{currency}</span>\n </span>\n ) : (\n <span className={`${DISPLAY_FACE} ${s.crypto} text-foreground/90`}>{cryptoDisplay}</span>\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n /** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed\n * readable regardless of the artwork or the viewer's theme. */\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n /** Theme-aware card backgrounds (TokenCard). */\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n} as const;\n\n/**\n * Overlay/pill price content — fiat leads, crypto trails dimmer, middot-\n * separated; stablecoins collapse to fiat + symbol alone. Renders only the\n * inner fragment: callers own their own pill container (background, blur,\n * border, padding), which intentionally differs between hosts (see\n * `tone`) rather than being forced into one visual treatment.\n */\nexport function PriceChipContent({\n amountFormatted,\n currency,\n usdValue,\n tone,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n tone: keyof typeof CHIP_TONES;\n}) {\n if (!amountFormatted) return null;\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const stable = isStableCurrency(currency);\n\n if (!usdValue) {\n return (\n <>\n {currency && <CurrencyIcon symbol={currency} size={13} />}\n {cryptoDisplay}\n </>\n );\n }\n\n const t = CHIP_TONES[tone];\n return (\n <>\n {usdValue}\n <span className={t.dot}>·</span>\n <span className={`inline-flex items-center gap-1 font-semibold ${t.text}`}>\n {currency && <CurrencyIcon symbol={currency} size={12} />}\n {stable ? currency : cryptoDisplay}\n </span>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Currency icon in the soft circular chip used throughout the wallet UI —
|
|
5
|
+
* reads as a coin, not a stray glyph floating next to text. */
|
|
6
|
+
declare function CoinChip({ symbol, size }: {
|
|
7
|
+
symbol: string | null | undefined;
|
|
8
|
+
size: number;
|
|
9
|
+
}): react_jsx_runtime.JSX.Element;
|
|
10
|
+
declare const DUAL_PRICE_SCALES: {
|
|
11
|
+
/** Full-width hero contexts: AssetMarketplacePanel's main price. Has room
|
|
12
|
+
* to spell out the currency ("0.07 ETH"), not just imply it via icon. */
|
|
13
|
+
readonly hero: {
|
|
14
|
+
readonly fiat: "text-4xl";
|
|
15
|
+
readonly crypto: "text-2xl";
|
|
16
|
+
readonly chip: 16;
|
|
17
|
+
readonly stableChip: 13;
|
|
18
|
+
readonly divider: "h-7";
|
|
19
|
+
readonly showCurrencyLabel: true;
|
|
20
|
+
};
|
|
21
|
+
/** Card contexts: ListingCard's full variant — denser, the coin icon
|
|
22
|
+
* already conveys the currency, a text label would be redundant. */
|
|
23
|
+
readonly card: {
|
|
24
|
+
readonly fiat: "text-lg";
|
|
25
|
+
readonly crypto: "text-sm";
|
|
26
|
+
readonly chip: 11;
|
|
27
|
+
readonly stableChip: 9;
|
|
28
|
+
readonly divider: "h-4";
|
|
29
|
+
readonly showCurrencyLabel: false;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Equal-weight dual price: fiat and the on-chain currency shown as peers,
|
|
34
|
+
* not primary/afterthought — this platform's audience spans non-crypto
|
|
35
|
+
* newcomers who read fiat and crypto-native buyers who read the token
|
|
36
|
+
* amount. Both use the brand display face at a real step-down in scale so
|
|
37
|
+
* the pairing reads as "two related numbers," not one dominant + one
|
|
38
|
+
* caption. Falls back to crypto-only when no USD rate is available. When
|
|
39
|
+
* the currency is itself a USD-pegged stablecoin, the crypto amount
|
|
40
|
+
* collapses to a small currency badge — showing "$12.00" beside "12.00
|
|
41
|
+
* USDC" would just be the same number twice.
|
|
42
|
+
*/
|
|
43
|
+
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, }: {
|
|
44
|
+
amountFormatted: string | null | undefined;
|
|
45
|
+
currency: string | null | undefined;
|
|
46
|
+
usdValue?: string | null;
|
|
47
|
+
scale: keyof typeof DUAL_PRICE_SCALES;
|
|
48
|
+
trailing?: ReactNode;
|
|
49
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
50
|
+
declare const CHIP_TONES: {
|
|
51
|
+
/** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed
|
|
52
|
+
* readable regardless of the artwork or the viewer's theme. */
|
|
53
|
+
readonly "overlay-dark": {
|
|
54
|
+
readonly dot: "text-white/30";
|
|
55
|
+
readonly text: "text-white/65";
|
|
56
|
+
};
|
|
57
|
+
/** Theme-aware card backgrounds (TokenCard). */
|
|
58
|
+
readonly card: {
|
|
59
|
+
readonly dot: "text-muted-foreground/50";
|
|
60
|
+
readonly text: "text-muted-foreground";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Overlay/pill price content — fiat leads, crypto trails dimmer, middot-
|
|
65
|
+
* separated; stablecoins collapse to fiat + symbol alone. Renders only the
|
|
66
|
+
* inner fragment: callers own their own pill container (background, blur,
|
|
67
|
+
* border, padding), which intentionally differs between hosts (see
|
|
68
|
+
* `tone`) rather than being forced into one visual treatment.
|
|
69
|
+
*/
|
|
70
|
+
declare function PriceChipContent({ amountFormatted, currency, usdValue, tone, }: {
|
|
71
|
+
amountFormatted: string | null | undefined;
|
|
72
|
+
currency: string | null | undefined;
|
|
73
|
+
usdValue?: string | null;
|
|
74
|
+
tone: keyof typeof CHIP_TONES;
|
|
75
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
76
|
+
|
|
77
|
+
export { CoinChip, DualPrice, PriceChipContent };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Currency icon in the soft circular chip used throughout the wallet UI —
|
|
5
|
+
* reads as a coin, not a stray glyph floating next to text. */
|
|
6
|
+
declare function CoinChip({ symbol, size }: {
|
|
7
|
+
symbol: string | null | undefined;
|
|
8
|
+
size: number;
|
|
9
|
+
}): react_jsx_runtime.JSX.Element;
|
|
10
|
+
declare const DUAL_PRICE_SCALES: {
|
|
11
|
+
/** Full-width hero contexts: AssetMarketplacePanel's main price. Has room
|
|
12
|
+
* to spell out the currency ("0.07 ETH"), not just imply it via icon. */
|
|
13
|
+
readonly hero: {
|
|
14
|
+
readonly fiat: "text-4xl";
|
|
15
|
+
readonly crypto: "text-2xl";
|
|
16
|
+
readonly chip: 16;
|
|
17
|
+
readonly stableChip: 13;
|
|
18
|
+
readonly divider: "h-7";
|
|
19
|
+
readonly showCurrencyLabel: true;
|
|
20
|
+
};
|
|
21
|
+
/** Card contexts: ListingCard's full variant — denser, the coin icon
|
|
22
|
+
* already conveys the currency, a text label would be redundant. */
|
|
23
|
+
readonly card: {
|
|
24
|
+
readonly fiat: "text-lg";
|
|
25
|
+
readonly crypto: "text-sm";
|
|
26
|
+
readonly chip: 11;
|
|
27
|
+
readonly stableChip: 9;
|
|
28
|
+
readonly divider: "h-4";
|
|
29
|
+
readonly showCurrencyLabel: false;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Equal-weight dual price: fiat and the on-chain currency shown as peers,
|
|
34
|
+
* not primary/afterthought — this platform's audience spans non-crypto
|
|
35
|
+
* newcomers who read fiat and crypto-native buyers who read the token
|
|
36
|
+
* amount. Both use the brand display face at a real step-down in scale so
|
|
37
|
+
* the pairing reads as "two related numbers," not one dominant + one
|
|
38
|
+
* caption. Falls back to crypto-only when no USD rate is available. When
|
|
39
|
+
* the currency is itself a USD-pegged stablecoin, the crypto amount
|
|
40
|
+
* collapses to a small currency badge — showing "$12.00" beside "12.00
|
|
41
|
+
* USDC" would just be the same number twice.
|
|
42
|
+
*/
|
|
43
|
+
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, }: {
|
|
44
|
+
amountFormatted: string | null | undefined;
|
|
45
|
+
currency: string | null | undefined;
|
|
46
|
+
usdValue?: string | null;
|
|
47
|
+
scale: keyof typeof DUAL_PRICE_SCALES;
|
|
48
|
+
trailing?: ReactNode;
|
|
49
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
50
|
+
declare const CHIP_TONES: {
|
|
51
|
+
/** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed
|
|
52
|
+
* readable regardless of the artwork or the viewer's theme. */
|
|
53
|
+
readonly "overlay-dark": {
|
|
54
|
+
readonly dot: "text-white/30";
|
|
55
|
+
readonly text: "text-white/65";
|
|
56
|
+
};
|
|
57
|
+
/** Theme-aware card backgrounds (TokenCard). */
|
|
58
|
+
readonly card: {
|
|
59
|
+
readonly dot: "text-muted-foreground/50";
|
|
60
|
+
readonly text: "text-muted-foreground";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Overlay/pill price content — fiat leads, crypto trails dimmer, middot-
|
|
65
|
+
* separated; stablecoins collapse to fiat + symbol alone. Renders only the
|
|
66
|
+
* inner fragment: callers own their own pill container (background, blur,
|
|
67
|
+
* border, padding), which intentionally differs between hosts (see
|
|
68
|
+
* `tone`) rather than being forced into one visual treatment.
|
|
69
|
+
*/
|
|
70
|
+
declare function PriceChipContent({ amountFormatted, currency, usdValue, tone, }: {
|
|
71
|
+
amountFormatted: string | null | undefined;
|
|
72
|
+
currency: string | null | undefined;
|
|
73
|
+
usdValue?: string | null;
|
|
74
|
+
tone: keyof typeof CHIP_TONES;
|
|
75
|
+
}): react_jsx_runtime.JSX.Element | null;
|
|
76
|
+
|
|
77
|
+
export { CoinChip, DualPrice, PriceChipContent };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CurrencyIcon } from "./currency-icon.js";
|
|
4
|
+
import { formatDisplayPrice, isStableCurrency } from "../utils/format.js";
|
|
5
|
+
function CoinChip({ symbol, size }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
"span",
|
|
8
|
+
{
|
|
9
|
+
className: "grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]",
|
|
10
|
+
style: { width: size + 10, height: size + 10 },
|
|
11
|
+
children: /* @__PURE__ */ jsx(CurrencyIcon, { symbol: symbol ?? "", size })
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const DISPLAY_FACE = "font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums";
|
|
16
|
+
const DUAL_PRICE_SCALES = {
|
|
17
|
+
/** Full-width hero contexts: AssetMarketplacePanel's main price. Has room
|
|
18
|
+
* to spell out the currency ("0.07 ETH"), not just imply it via icon. */
|
|
19
|
+
hero: { fiat: "text-4xl", crypto: "text-2xl", chip: 16, stableChip: 13, divider: "h-7", showCurrencyLabel: true },
|
|
20
|
+
/** Card contexts: ListingCard's full variant — denser, the coin icon
|
|
21
|
+
* already conveys the currency, a text label would be redundant. */
|
|
22
|
+
card: { fiat: "text-lg", crypto: "text-sm", chip: 11, stableChip: 9, divider: "h-4", showCurrencyLabel: false }
|
|
23
|
+
};
|
|
24
|
+
function DualPrice({
|
|
25
|
+
amountFormatted,
|
|
26
|
+
currency,
|
|
27
|
+
usdValue,
|
|
28
|
+
scale,
|
|
29
|
+
trailing
|
|
30
|
+
}) {
|
|
31
|
+
if (!amountFormatted) return null;
|
|
32
|
+
const s = DUAL_PRICE_SCALES[scale];
|
|
33
|
+
const cryptoDisplay = formatDisplayPrice(amountFormatted);
|
|
34
|
+
if (!usdValue) {
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-2.5 ${DISPLAY_FACE} ${s.fiat}`, children: [
|
|
36
|
+
/* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: s.chip }),
|
|
37
|
+
cryptoDisplay,
|
|
38
|
+
trailing && /* @__PURE__ */ jsx("span", { className: "ml-0.5", children: trailing })
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
const stable = isStableCurrency(currency);
|
|
42
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
43
|
+
/* @__PURE__ */ jsx("span", { className: `${DISPLAY_FACE} ${s.fiat}`, children: usdValue }),
|
|
44
|
+
!stable && /* @__PURE__ */ jsx("span", { className: `${s.divider} w-px bg-border/60 shrink-0` }),
|
|
45
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
46
|
+
/* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: stable ? s.stableChip : s.chip }),
|
|
47
|
+
stable ? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-muted-foreground", children: currency }) : s.showCurrencyLabel ? /* @__PURE__ */ jsxs("span", { className: "flex items-baseline gap-1.5", children: [
|
|
48
|
+
/* @__PURE__ */ jsx("span", { className: `${DISPLAY_FACE} ${s.crypto} text-foreground/90`, children: cryptoDisplay }),
|
|
49
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-muted-foreground/70", children: currency })
|
|
50
|
+
] }) : /* @__PURE__ */ jsx("span", { className: `${DISPLAY_FACE} ${s.crypto} text-foreground/90`, children: cryptoDisplay })
|
|
51
|
+
] }),
|
|
52
|
+
trailing && /* @__PURE__ */ jsx("span", { className: "ml-0.5", children: trailing })
|
|
53
|
+
] });
|
|
54
|
+
}
|
|
55
|
+
const CHIP_TONES = {
|
|
56
|
+
/** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed
|
|
57
|
+
* readable regardless of the artwork or the viewer's theme. */
|
|
58
|
+
"overlay-dark": { dot: "text-white/30", text: "text-white/65" },
|
|
59
|
+
/** Theme-aware card backgrounds (TokenCard). */
|
|
60
|
+
card: { dot: "text-muted-foreground/50", text: "text-muted-foreground" }
|
|
61
|
+
};
|
|
62
|
+
function PriceChipContent({
|
|
63
|
+
amountFormatted,
|
|
64
|
+
currency,
|
|
65
|
+
usdValue,
|
|
66
|
+
tone
|
|
67
|
+
}) {
|
|
68
|
+
if (!amountFormatted) return null;
|
|
69
|
+
const cryptoDisplay = formatDisplayPrice(amountFormatted);
|
|
70
|
+
const stable = isStableCurrency(currency);
|
|
71
|
+
if (!usdValue) {
|
|
72
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
73
|
+
currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: currency, size: 13 }),
|
|
74
|
+
cryptoDisplay
|
|
75
|
+
] });
|
|
76
|
+
}
|
|
77
|
+
const t = CHIP_TONES[tone];
|
|
78
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
79
|
+
usdValue,
|
|
80
|
+
/* @__PURE__ */ jsx("span", { className: t.dot, children: "\xB7" }),
|
|
81
|
+
/* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1 font-semibold ${t.text}`, children: [
|
|
82
|
+
currency && /* @__PURE__ */ jsx(CurrencyIcon, { symbol: currency, size: 12 }),
|
|
83
|
+
stable ? currency : cryptoDisplay
|
|
84
|
+
] })
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
CoinChip,
|
|
89
|
+
DualPrice,
|
|
90
|
+
PriceChipContent
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=dual-price.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/dual-price.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\nimport { formatDisplayPrice, isStableCurrency } from \"../utils/format.js\";\n\n/** Currency icon in the soft circular chip used throughout the wallet UI —\n * reads as a coin, not a stray glyph floating next to text. */\nexport function CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\nconst DISPLAY_FACE = \"font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n /** Full-width hero contexts: AssetMarketplacePanel's main price. Has room\n * to spell out the currency (\"0.07 ETH\"), not just imply it via icon. */\n hero: { fiat: \"text-4xl\", crypto: \"text-2xl\", chip: 16, stableChip: 13, divider: \"h-7\", showCurrencyLabel: true },\n /** Card contexts: ListingCard's full variant — denser, the coin icon\n * already conveys the currency, a text label would be redundant. */\n card: { fiat: \"text-lg\", crypto: \"text-sm\", chip: 11, stableChip: 9, divider: \"h-4\", showCurrencyLabel: false },\n} as const;\n\n/**\n * Equal-weight dual price: fiat and the on-chain currency shown as peers,\n * not primary/afterthought — this platform's audience spans non-crypto\n * newcomers who read fiat and crypto-native buyers who read the token\n * amount. Both use the brand display face at a real step-down in scale so\n * the pairing reads as \"two related numbers,\" not one dominant + one\n * caption. Falls back to crypto-only when no USD rate is available. When\n * the currency is itself a USD-pegged stablecoin, the crypto amount\n * collapses to a small currency badge — showing \"$12.00\" beside \"12.00\n * USDC\" would just be the same number twice.\n */\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n scale: keyof typeof DUAL_PRICE_SCALES;\n trailing?: ReactNode;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n\n if (!usdValue) {\n return (\n <div className={`flex items-center gap-2.5 ${DISPLAY_FACE} ${s.fiat}`}>\n <CoinChip symbol={currency} size={s.chip} />\n {cryptoDisplay}\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2.5\">\n <span className={`${DISPLAY_FACE} ${s.fiat}`}>{usdValue}</span>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={stable ? s.stableChip : s.chip} />\n {stable ? (\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n ) : s.showCurrencyLabel ? (\n <span className=\"flex items-baseline gap-1.5\">\n <span className={`${DISPLAY_FACE} ${s.crypto} text-foreground/90`}>{cryptoDisplay}</span>\n <span className=\"text-sm font-semibold text-muted-foreground/70\">{currency}</span>\n </span>\n ) : (\n <span className={`${DISPLAY_FACE} ${s.crypto} text-foreground/90`}>{cryptoDisplay}</span>\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n /** Full-bleed image overlays (AssetCard) — fixed dark glass, guaranteed\n * readable regardless of the artwork or the viewer's theme. */\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n /** Theme-aware card backgrounds (TokenCard). */\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n} as const;\n\n/**\n * Overlay/pill price content — fiat leads, crypto trails dimmer, middot-\n * separated; stablecoins collapse to fiat + symbol alone. Renders only the\n * inner fragment: callers own their own pill container (background, blur,\n * border, padding), which intentionally differs between hosts (see\n * `tone`) rather than being forced into one visual treatment.\n */\nexport function PriceChipContent({\n amountFormatted,\n currency,\n usdValue,\n tone,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n tone: keyof typeof CHIP_TONES;\n}) {\n if (!amountFormatted) return null;\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const stable = isStableCurrency(currency);\n\n if (!usdValue) {\n return (\n <>\n {currency && <CurrencyIcon symbol={currency} size={13} />}\n {cryptoDisplay}\n </>\n );\n }\n\n const t = CHIP_TONES[tone];\n return (\n <>\n {usdValue}\n <span className={t.dot}>·</span>\n <span className={`inline-flex items-center gap-1 font-semibold ${t.text}`}>\n {currency && <CurrencyIcon symbol={currency} size={12} />}\n {stable ? currency : cryptoDisplay}\n </span>\n </>\n );\n}\n"],"mappings":";AAcM,SA6GA,UA7GA,KA8CA,YA9CA;AAXN,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB,wBAAwB;AAI9C,SAAS,SAAS,EAAE,QAAQ,KAAK,GAAwD;AAC9F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,OAAO,OAAO,IAAI,QAAQ,OAAO,GAAG;AAAA,MAE7C,8BAAC,gBAAa,QAAQ,UAAU,IAAI,MAAY;AAAA;AAAA,EAClD;AAEJ;AAEA,MAAM,eAAe;AAErB,MAAM,oBAAoB;AAAA;AAAA;AAAA,EAGxB,MAAM,EAAE,MAAM,YAAY,QAAQ,YAAY,MAAM,IAAI,YAAY,IAAI,SAAS,OAAO,mBAAmB,KAAK;AAAA;AAAA;AAAA,EAGhH,MAAM,EAAE,MAAM,WAAW,QAAQ,WAAW,MAAM,IAAI,YAAY,GAAG,SAAS,OAAO,mBAAmB,MAAM;AAChH;AAaO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,MAAI,CAAC,gBAAiB,QAAO;AAC7B,QAAM,IAAI,kBAAkB,KAAK;AACjC,QAAM,gBAAgB,mBAAmB,eAAe;AAExD,MAAI,CAAC,UAAU;AACb,WACE,qBAAC,SAAI,WAAW,6BAA6B,YAAY,IAAI,EAAE,IAAI,IACjE;AAAA,0BAAC,YAAS,QAAQ,UAAU,MAAM,EAAE,MAAM;AAAA,MACzC;AAAA,MACA,YAAY,oBAAC,UAAK,WAAU,UAAU,oBAAS;AAAA,OAClD;AAAA,EAEJ;AAEA,QAAM,SAAS,iBAAiB,QAAQ;AACxC,SACE,qBAAC,SAAI,WAAU,6BACb;AAAA,wBAAC,UAAK,WAAW,GAAG,YAAY,IAAI,EAAE,IAAI,IAAK,oBAAS;AAAA,IACvD,CAAC,UAAU,oBAAC,UAAK,WAAW,GAAG,EAAE,OAAO,+BAA+B;AAAA,IACxE,qBAAC,UAAK,WAAU,oCACd;AAAA,0BAAC,YAAS,QAAQ,UAAU,MAAM,SAAS,EAAE,aAAa,EAAE,MAAM;AAAA,MACjE,SACC,oBAAC,UAAK,WAAU,+CAA+C,oBAAS,IACtE,EAAE,oBACJ,qBAAC,UAAK,WAAU,+BACd;AAAA,4BAAC,UAAK,WAAW,GAAG,YAAY,IAAI,EAAE,MAAM,uBAAwB,yBAAc;AAAA,QAClF,oBAAC,UAAK,WAAU,kDAAkD,oBAAS;AAAA,SAC7E,IAEA,oBAAC,UAAK,WAAW,GAAG,YAAY,IAAI,EAAE,MAAM,uBAAwB,yBAAc;AAAA,OAEtF;AAAA,IACC,YAAY,oBAAC,UAAK,WAAU,UAAU,oBAAS;AAAA,KAClD;AAEJ;AAEA,MAAM,aAAa;AAAA;AAAA;AAAA,EAGjB,gBAAgB,EAAE,KAAK,iBAAiB,MAAM,gBAAgB;AAAA;AAAA,EAE9D,MAAM,EAAE,KAAK,4BAA4B,MAAM,wBAAwB;AACzE;AASO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,MAAI,CAAC,gBAAiB,QAAO;AAC7B,QAAM,gBAAgB,mBAAmB,eAAe;AACxD,QAAM,SAAS,iBAAiB,QAAQ;AAExC,MAAI,CAAC,UAAU;AACb,WACE,iCACG;AAAA,kBAAY,oBAAC,gBAAa,QAAQ,UAAU,MAAM,IAAI;AAAA,MACtD;AAAA,OACH;AAAA,EAEJ;AAEA,QAAM,IAAI,WAAW,IAAI;AACzB,SACE,iCACG;AAAA;AAAA,IACD,oBAAC,UAAK,WAAW,EAAE,KAAK,kBAAC;AAAA,IACzB,qBAAC,UAAK,WAAW,gDAAgD,EAAE,IAAI,IACpE;AAAA,kBAAY,oBAAC,gBAAa,QAAQ,UAAU,MAAM,IAAI;AAAA,MACtD,SAAS,WAAW;AAAA,OACvB;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -43,6 +43,7 @@ var import_animated_token_media = require("./animated-token-media.js");
|
|
|
43
43
|
var import_cn = require("../utils/cn.js");
|
|
44
44
|
var import_ipfs = require("../utils/ipfs.js");
|
|
45
45
|
var import_format = require("../utils/format.js");
|
|
46
|
+
var import_dual_price = require("./dual-price.js");
|
|
46
47
|
var import_time = require("../utils/time.js");
|
|
47
48
|
var import_living_render_collections = require("../data/living-render-collections.js");
|
|
48
49
|
function PriceLine({
|
|
@@ -66,40 +67,6 @@ function PriceLine({
|
|
|
66
67
|
] })
|
|
67
68
|
] });
|
|
68
69
|
}
|
|
69
|
-
function CoinChip({ symbol, size }) {
|
|
70
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
71
|
-
"span",
|
|
72
|
-
{
|
|
73
|
-
className: "grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]",
|
|
74
|
-
style: { width: size + 10, height: size + 10 },
|
|
75
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: symbol ?? "", size })
|
|
76
|
-
}
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
function CardDualPrice({
|
|
80
|
-
amountFormatted,
|
|
81
|
-
currency,
|
|
82
|
-
usdValue
|
|
83
|
-
}) {
|
|
84
|
-
if (!amountFormatted) return null;
|
|
85
|
-
const cryptoDisplay = (0, import_format.formatDisplayPrice)(amountFormatted);
|
|
86
|
-
const displayFace = "font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums";
|
|
87
|
-
if (!usdValue) {
|
|
88
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: `flex items-center gap-1.5 ${displayFace} text-lg`, children: [
|
|
89
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: 11 }),
|
|
90
|
-
cryptoDisplay
|
|
91
|
-
] });
|
|
92
|
-
}
|
|
93
|
-
const stable = (0, import_format.isStableCurrency)(currency);
|
|
94
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
95
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${displayFace} text-lg`, children: usdValue }),
|
|
96
|
-
!stable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-4 w-px bg-border/60 shrink-0" }),
|
|
97
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
98
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: stable ? 9 : 11 }),
|
|
99
|
-
stable ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-2xs font-semibold text-muted-foreground", children: currency }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${displayFace} text-sm text-foreground/80`, children: cryptoDisplay })
|
|
100
|
-
] })
|
|
101
|
-
] });
|
|
102
|
-
}
|
|
103
70
|
function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }) {
|
|
104
71
|
const order = rawOrder;
|
|
105
72
|
const [imgError, setImgError] = (0, import_react.useState)(false);
|
|
@@ -161,7 +128,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
161
128
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-semibold text-base truncate leading-snug", children: name }),
|
|
162
129
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground truncate leading-snug mt-0.5", children: order.token?.description ? order.token.description : `#${order.nftTokenId}` })
|
|
163
130
|
] }),
|
|
164
|
-
order.price?.formatted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
order.price?.formatted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dual_price.DualPrice, { amountFormatted: order.price.formatted, currency: order.price.currency, usdValue, scale: "card" }),
|
|
165
132
|
showActionBar && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
166
133
|
isListing ? primaryAction ? primaryAction : onBuy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
167
134
|
"button",
|
|
@@ -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, isStableCurrency } 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\n/** Compact grid thumbnails: too little room for the full dual-price\n * treatment, so this stays fiat-primary + a small crypto caption. */\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\n/** Coin icon in a soft circular chip — same treatment as AssetMarketplacePanel,\n * scaled down for card density. */\nfunction CoinChip({ symbol, size }: { symbol: string | null | undefined; size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]\"\n style={{ width: size + 10, height: size + 10 }}\n >\n <CurrencyIcon symbol={symbol ?? \"\"} size={size} />\n </span>\n );\n}\n\n/**\n * Full-card dual price: fiat and the on-chain currency as equal-weight\n * peers (same language as AssetMarketplacePanel's PrimaryPrice), scaled\n * down for card density — no \"PRICE\" eyebrow label, no divider text\n * duplicating what the coin chip already conveys.\n */\nfunction CardDualPrice({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const displayFace = \"font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums\";\n\n if (!usdValue) {\n return (\n <p className={`flex items-center gap-1.5 ${displayFace} text-lg`}>\n <CoinChip symbol={currency} size={11} />\n {cryptoDisplay}\n </p>\n );\n }\n\n const stable = isStableCurrency(currency);\n return (\n <div className=\"flex items-center gap-2\">\n <span className={`${displayFace} text-lg`}>{usdValue}</span>\n {!stable && <span className=\"h-4 w-px bg-border/60 shrink-0\" />}\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={stable ? 9 : 11} />\n {stable ? (\n <span className=\"text-2xs font-semibold text-muted-foreground\">{currency}</span>\n ) : (\n <span className={`${displayFace} text-sm text-foreground/80`}>{cryptoDisplay}</span>\n )}\n </span>\n </div>\n );\n}\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 <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── 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 {order.price?.formatted && (\n <CardDualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} />\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"]}
|
|
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, isStableCurrency } from \"../utils/format.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport 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\n/** Compact grid thumbnails: too little room for the full dual-price\n * treatment, so this stays fiat-primary + a small crypto caption. */\nfunction PriceLine({\n amountFormatted, currency, usdValue,\n}: {\n amountFormatted: string | null | undefined;\n currency: string | null | undefined;\n usdValue?: string | null;\n}) {\n if (!amountFormatted) return null;\n if (!usdValue) {\n return (\n <p className=\"text-2xs font-bold price-value inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={11} />}\n {formatDisplayPrice(amountFormatted)}\n </p>\n );\n }\n const stable = isStableCurrency(currency);\n return (\n <>\n <p className=\"text-2xs font-bold price-value\">\n {usdValue}\n </p>\n <p className=\"text-2xs text-muted-foreground/70 inline-flex items-center gap-1\">\n {currency && <CurrencyIcon symbol={currency} size={10} />}\n {stable ? currency : `${formatDisplayPrice(amountFormatted)} ${currency}`}\n </p>\n </>\n );\n}\n\nexport interface ListingCardProps {\n order: ApiOrder;\n inCart?: boolean;\n onBuy?: (order: ApiOrder) => void;\n onCart?: (order: ApiOrder) => void;\n /** 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 <PriceLine amountFormatted={order.price?.formatted} currency={order.price?.currency} usdValue={usdValue} />\n <p className=\"text-2xs text-muted-foreground\">{timeAgo(order.createdAt)}</p>\n </div>\n </Link>\n </MotionCard>\n );\n }\n\n // ─── 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 {order.price?.formatted && (\n <DualPrice amountFormatted={order.price.formatted} currency={order.price.currency} usdValue={usdValue} scale=\"card\" />\n )}\n\n {showActionBar && (\n <div className=\"flex items-center gap-1.5\">\n {isListing ? (\n primaryAction ? (\n primaryAction\n ) : onBuy ? (\n <div className=\"btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9\">\n <button\n className=\"w-full h-full rounded-[9px] bg-background flex items-center justify-center gap-1.5 text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n onClick={(e) => { e.preventDefault(); onBuy(order); }}\n >\n <Zap className=\"h-3.5 w-3.5 shrink-0\" /> Buy\n </button>\n </div>\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View\n </Link>\n )\n ) : (\n <Link\n href={assetHref}\n className=\"flex-1 h-9 inline-flex items-center justify-center gap-1.5 rounded-[9px] border border-border bg-background text-xs font-semibold text-foreground hover:bg-muted/60 transition-all active:scale-[0.98]\"\n >\n <ArrowUpRight className=\"h-3.5 w-3.5 shrink-0\" /> View asset\n </Link>\n )}\n {onCart && (\n <button\n className={cn(\n \"min-h-11 min-w-11 shrink-0 rounded-[9px] border flex items-center justify-center transition-colors\",\n inCart\n ? \"border-brand-orange/50 bg-brand-orange/10 text-brand-orange\"\n : \"border-border bg-background hover:bg-muted text-foreground\"\n )}\n onClick={(e) => { e.preventDefault(); if (!inCart) onCart(order); }}\n disabled={inCart}\n aria-label={inCart ? \"Added to cart\" : \"Add to cart\"}\n >\n {inCart ? <Check className=\"h-3.5 w-3.5\" /> : <ShoppingCart className=\"h-3.5 w-3.5\" />}\n </button>\n )}\n {overflowMenu}\n </div>\n )}\n </div>\n </Link>\n </MotionCard>\n );\n}\n\nexport function ListingCardSkeleton() {\n return (\n <div className=\"card-base\">\n <div className=\"aspect-square w-full bg-muted animate-pulse\" />\n <div className=\"p-3 space-y-2.5\">\n <div className=\"space-y-1\">\n <div className=\"h-4 w-3/4 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-1/2 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-6 w-1/2 bg-muted animate-pulse rounded\" />\n <div className=\"h-3 w-2/3 bg-muted animate-pulse rounded\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
|
@@ -9,6 +9,7 @@ import { AnimatedTokenMedia } from "./animated-token-media.js";
|
|
|
9
9
|
import { cn } from "../utils/cn.js";
|
|
10
10
|
import { ipfsToHttp } from "../utils/ipfs.js";
|
|
11
11
|
import { formatDisplayPrice, isStableCurrency } from "../utils/format.js";
|
|
12
|
+
import { DualPrice } from "./dual-price.js";
|
|
12
13
|
import { timeAgo } from "../utils/time.js";
|
|
13
14
|
import { isLivingRenderCollection } from "../data/living-render-collections.js";
|
|
14
15
|
function PriceLine({
|
|
@@ -32,40 +33,6 @@ function PriceLine({
|
|
|
32
33
|
] })
|
|
33
34
|
] });
|
|
34
35
|
}
|
|
35
|
-
function CoinChip({ symbol, size }) {
|
|
36
|
-
return /* @__PURE__ */ jsx(
|
|
37
|
-
"span",
|
|
38
|
-
{
|
|
39
|
-
className: "grid shrink-0 place-items-center rounded-full bg-foreground/[0.06]",
|
|
40
|
-
style: { width: size + 10, height: size + 10 },
|
|
41
|
-
children: /* @__PURE__ */ jsx(CurrencyIcon, { symbol: symbol ?? "", size })
|
|
42
|
-
}
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
function CardDualPrice({
|
|
46
|
-
amountFormatted,
|
|
47
|
-
currency,
|
|
48
|
-
usdValue
|
|
49
|
-
}) {
|
|
50
|
-
if (!amountFormatted) return null;
|
|
51
|
-
const cryptoDisplay = formatDisplayPrice(amountFormatted);
|
|
52
|
-
const displayFace = "font-[family-name:var(--font-display)] font-extrabold tracking-tight tabular-nums";
|
|
53
|
-
if (!usdValue) {
|
|
54
|
-
return /* @__PURE__ */ jsxs("p", { className: `flex items-center gap-1.5 ${displayFace} text-lg`, children: [
|
|
55
|
-
/* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: 11 }),
|
|
56
|
-
cryptoDisplay
|
|
57
|
-
] });
|
|
58
|
-
}
|
|
59
|
-
const stable = isStableCurrency(currency);
|
|
60
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
61
|
-
/* @__PURE__ */ jsx("span", { className: `${displayFace} text-lg`, children: usdValue }),
|
|
62
|
-
!stable && /* @__PURE__ */ jsx("span", { className: "h-4 w-px bg-border/60 shrink-0" }),
|
|
63
|
-
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
64
|
-
/* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: stable ? 9 : 11 }),
|
|
65
|
-
stable ? /* @__PURE__ */ jsx("span", { className: "text-2xs font-semibold text-muted-foreground", children: currency }) : /* @__PURE__ */ jsx("span", { className: `${displayFace} text-sm text-foreground/80`, children: cryptoDisplay })
|
|
66
|
-
] })
|
|
67
|
-
] });
|
|
68
|
-
}
|
|
69
36
|
function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowMenu, primaryAction, compact = false, imageUrl, usdValue }) {
|
|
70
37
|
const order = rawOrder;
|
|
71
38
|
const [imgError, setImgError] = useState(false);
|
|
@@ -127,7 +94,7 @@ function ListingCard({ order: rawOrder, inCart = false, onBuy, onCart, overflowM
|
|
|
127
94
|
/* @__PURE__ */ jsx("p", { className: "font-semibold text-base truncate leading-snug", children: name }),
|
|
128
95
|
/* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground truncate leading-snug mt-0.5", children: order.token?.description ? order.token.description : `#${order.nftTokenId}` })
|
|
129
96
|
] }),
|
|
130
|
-
order.price?.formatted && /* @__PURE__ */ jsx(
|
|
97
|
+
order.price?.formatted && /* @__PURE__ */ jsx(DualPrice, { amountFormatted: order.price.formatted, currency: order.price.currency, usdValue, scale: "card" }),
|
|
131
98
|
showActionBar && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
132
99
|
isListing ? primaryAction ? primaryAction : onBuy ? /* @__PURE__ */ jsx("div", { className: "btn-border-animated p-[1.5px] rounded-[10px] flex-1 h-9", children: /* @__PURE__ */ jsxs(
|
|
133
100
|
"button",
|