@medialane/ui 0.137.1 → 0.139.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/coin-launch-preview.cjs +30 -23
- package/dist/components/coin-launch-preview.cjs.map +1 -1
- package/dist/components/coin-launch-preview.d.cts +1 -0
- package/dist/components/coin-launch-preview.d.ts +1 -0
- package/dist/components/coin-launch-preview.js +30 -23
- package/dist/components/coin-launch-preview.js.map +1 -1
- package/dist/components/coin-row.cjs +10 -2
- package/dist/components/coin-row.cjs.map +1 -1
- package/dist/components/coin-row.js +10 -2
- package/dist/components/coin-row.js.map +1 -1
- package/dist/components/coins-explorer.cjs +46 -105
- package/dist/components/coins-explorer.cjs.map +1 -1
- package/dist/components/coins-explorer.d.cts +7 -2
- package/dist/components/coins-explorer.d.ts +7 -2
- package/dist/components/coins-explorer.js +49 -108
- package/dist/components/coins-explorer.js.map +1 -1
- package/dist/components/dual-price.cjs +17 -14
- package/dist/components/dual-price.cjs.map +1 -1
- package/dist/components/dual-price.d.cts +2 -1
- package/dist/components/dual-price.d.ts +2 -1
- package/dist/components/dual-price.js +17 -14
- package/dist/components/dual-price.js.map +1 -1
- package/dist/components/stat-tile.cjs +23 -15
- package/dist/components/stat-tile.cjs.map +1 -1
- package/dist/components/stat-tile.d.cts +6 -2
- package/dist/components/stat-tile.d.ts +6 -2
- package/dist/components/stat-tile.js +23 -15
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/data/coin-order.cjs +43 -0
- package/dist/data/coin-order.cjs.map +1 -0
- package/dist/data/coin-order.d.cts +6 -0
- package/dist/data/coin-order.d.ts +6 -0
- package/dist/data/coin-order.js +19 -0
- package/dist/data/coin-order.js.map +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -36,11 +36,14 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
36
36
|
var import_image = __toESM(require("./image.js"), 1);
|
|
37
37
|
var import_lucide_react = require("lucide-react");
|
|
38
38
|
var import_cn = require("../utils/cn.js");
|
|
39
|
-
|
|
39
|
+
var import_currency_icon = require("./currency-icon.js");
|
|
40
40
|
const COIN_GRADIENT = "linear-gradient(135deg, #f6608f, #fb8b46)";
|
|
41
|
+
function StatValue({ children }) {
|
|
42
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "inline-flex items-center gap-1 font-bold tabular-nums text-brand-maeve", children });
|
|
43
|
+
}
|
|
41
44
|
function CoinLaunchPreview({ data, className }) {
|
|
42
|
-
const { name, symbol, description, imageUrl, supplyHuman, quoteSymbol, teamPct } = data;
|
|
43
|
-
const marketCap = supplyHuman != null ? supplyHuman *
|
|
45
|
+
const { name, symbol, description, imageUrl, supplyHuman, price, quoteSymbol, teamPct } = data;
|
|
46
|
+
const marketCap = supplyHuman != null ? supplyHuman * price : null;
|
|
44
47
|
const yourCoins = supplyHuman != null ? supplyHuman * (teamPct / 100) : null;
|
|
45
48
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("rounded-2xl bg-muted/50 dark:bg-card overflow-hidden", className), children: [
|
|
46
49
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-5 pt-4", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "section-label", children: "Live preview" }) }),
|
|
@@ -53,40 +56,44 @@ function CoinLaunchPreview({ data, className }) {
|
|
|
53
56
|
] })
|
|
54
57
|
] }),
|
|
55
58
|
description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-3", children: description }) : null,
|
|
56
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "
|
|
59
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl bg-muted/50 dark:bg-muted/30 p-4 space-y-3", children: [
|
|
57
60
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
58
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs uppercase tracking-wide text-muted-foreground", children: "
|
|
59
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
60
|
-
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs uppercase tracking-wide text-muted-foreground", children: "Market cap" }),
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xl", children: marketCap != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(StatValue, { children: [
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: quoteSymbol, size: 18 }),
|
|
64
|
+
marketCap.toLocaleString(),
|
|
61
65
|
" ",
|
|
62
66
|
quoteSymbol
|
|
63
|
-
] })
|
|
67
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: "\u2014" }) })
|
|
64
68
|
] }),
|
|
65
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
66
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
67
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between text-sm border-t border-border/60 pt-3", children: [
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: "Launch price" }),
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 font-semibold tabular-nums", children: [
|
|
72
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: quoteSymbol, size: 14 }),
|
|
73
|
+
price,
|
|
74
|
+
" ",
|
|
75
|
+
quoteSymbol,
|
|
76
|
+
" / coin"
|
|
77
|
+
] })
|
|
72
78
|
] })
|
|
73
79
|
] }),
|
|
74
80
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
75
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex
|
|
76
|
-
teamPct > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: `${teamPct}%`, background: COIN_GRADIENT } }),
|
|
77
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex-1" })
|
|
78
|
-
] }),
|
|
79
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between text-2xs text-muted-foreground", children: [
|
|
81
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between text-sm", children: [
|
|
80
82
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-medium text-brand-rose", children: [
|
|
81
|
-
"You ",
|
|
83
|
+
"You keep ",
|
|
82
84
|
teamPct,
|
|
83
|
-
"%"
|
|
85
|
+
"%",
|
|
86
|
+
yourCoins != null ? ` \xB7 ${yourCoins.toLocaleString()} ${symbol || "coins"}` : ""
|
|
84
87
|
] }),
|
|
85
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
86
89
|
"Community ",
|
|
87
90
|
100 - teamPct,
|
|
88
91
|
"%"
|
|
89
92
|
] })
|
|
93
|
+
] }),
|
|
94
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex h-2.5 rounded-full overflow-hidden bg-muted-foreground/15", children: [
|
|
95
|
+
teamPct > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: `${teamPct}%`, background: COIN_GRADIENT } }),
|
|
96
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex-1" })
|
|
90
97
|
] })
|
|
91
98
|
] }),
|
|
92
99
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground/70", children: "Liquidity is locked forever \u2014 nobody can pull it, including us." })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/coin-launch-preview.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { TrendingUp } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface CoinPreviewData {\n name: string;\n symbol: string;\n description: string;\n\n imageUrl: string | null;\n\n supplyHuman: number | null;\n quoteSymbol: string;\n teamPct: number;\n}\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-launch-preview.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { TrendingUp } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\n\nexport interface CoinPreviewData {\n name: string;\n symbol: string;\n description: string;\n\n imageUrl: string | null;\n\n supplyHuman: number | null;\n price: number;\n quoteSymbol: string;\n teamPct: number;\n}\n\nconst COIN_GRADIENT = \"linear-gradient(135deg, #f6608f, #fb8b46)\";\n\nfunction StatValue({ children }: { children: React.ReactNode }) {\n return (\n <span className=\"inline-flex items-center gap-1 font-bold tabular-nums text-brand-maeve\">\n {children}\n </span>\n );\n}\n\nexport function CoinLaunchPreview({ data, className }: { data: CoinPreviewData; className?: string }) {\n const { name, symbol, description, imageUrl, supplyHuman, price, quoteSymbol, teamPct } = data;\n const marketCap = supplyHuman != null ? supplyHuman * price : null;\n const yourCoins = supplyHuman != null ? supplyHuman * (teamPct / 100) : null;\n\n return (\n <div className={cn(\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden\", className)}>\n <div className=\"px-5 pt-4\">\n <p className=\"section-label\">Live preview</p>\n </div>\n\n <div className=\"p-5 space-y-4\">\n\n <div className=\"flex items-center gap-3\">\n <div className=\"shrink-0 rounded-full p-[2px]\" style={{ background: COIN_GRADIENT }}>\n <div className=\"relative h-14 w-14 rounded-full overflow-hidden bg-card flex items-center justify-center\">\n {imageUrl ? (\n <Image src={imageUrl} alt=\"\" fill sizes=\"56px\" className=\"object-cover\" unoptimized />\n ) : (\n <TrendingUp className=\"h-6 w-6 text-brand-rose/70\" />\n )}\n </div>\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className={cn(\"font-bold text-lg leading-snug truncate\", !name && \"text-muted-foreground/50\")}>\n {name || \"Your coin\"}\n </p>\n <p className=\"text-sm text-muted-foreground tabular-nums\">{symbol ? `$${symbol}` : \"$SYMBOL\"}</p>\n </div>\n </div>\n\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed line-clamp-3\">{description}</p>\n ) : null}\n\n <div className=\"rounded-xl bg-muted/50 dark:bg-muted/30 p-4 space-y-3\">\n <div>\n <p className=\"text-2xs uppercase tracking-wide text-muted-foreground\">Market cap</p>\n <p className=\"text-2xl\">\n {marketCap != null ? (\n <StatValue>\n <CurrencyIcon symbol={quoteSymbol} size={18} />\n {marketCap.toLocaleString()} {quoteSymbol}\n </StatValue>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </p>\n </div>\n <div className=\"flex items-center justify-between text-sm border-t border-border/60 pt-3\">\n <span className=\"text-muted-foreground\">Launch price</span>\n <span className=\"inline-flex items-center gap-1 font-semibold tabular-nums\">\n <CurrencyIcon symbol={quoteSymbol} size={14} />\n {price} {quoteSymbol} / coin\n </span>\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium text-brand-rose\">\n You keep {teamPct}%{yourCoins != null ? ` · ${yourCoins.toLocaleString()} ${symbol || \"coins\"}` : \"\"}\n </span>\n <span className=\"text-muted-foreground\">Community {100 - teamPct}%</span>\n </div>\n <div className=\"flex h-2.5 rounded-full overflow-hidden bg-muted-foreground/15\">\n {teamPct > 0 && <div style={{ width: `${teamPct}%`, background: COIN_GRADIENT }} />}\n <div className=\"flex-1\" />\n </div>\n </div>\n\n <p className=\"text-2xs text-muted-foreground/70\">\n Liquidity is locked forever — nobody can pull it, including us.\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBI;AAtBJ,mBAAkB;AAClB,0BAA2B;AAC3B,gBAAmB;AACnB,2BAA6B;AAe7B,MAAM,gBAAgB;AAEtB,SAAS,UAAU,EAAE,SAAS,GAAkC;AAC9D,SACE,4CAAC,UAAK,WAAU,0EACb,UACH;AAEJ;AAEO,SAAS,kBAAkB,EAAE,MAAM,UAAU,GAAkD;AACpG,QAAM,EAAE,MAAM,QAAQ,aAAa,UAAU,aAAa,OAAO,aAAa,QAAQ,IAAI;AAC1F,QAAM,YAAY,eAAe,OAAO,cAAc,QAAQ;AAC9D,QAAM,YAAY,eAAe,OAAO,eAAe,UAAU,OAAO;AAExE,SACE,6CAAC,SAAI,eAAW,cAAG,wDAAwD,SAAS,GAClF;AAAA,gDAAC,SAAI,WAAU,aACb,sDAAC,OAAE,WAAU,iBAAgB,0BAAY,GAC3C;AAAA,IAEA,6CAAC,SAAI,WAAU,iBAEb;AAAA,mDAAC,SAAI,WAAU,2BACb;AAAA,oDAAC,SAAI,WAAU,iCAAgC,OAAO,EAAE,YAAY,cAAc,GAChF,sDAAC,SAAI,WAAU,4FACZ,qBACC,4CAAC,aAAAA,SAAA,EAAM,KAAK,UAAU,KAAI,IAAG,MAAI,MAAC,OAAM,QAAO,WAAU,gBAAe,aAAW,MAAC,IAEpF,4CAAC,kCAAW,WAAU,8BAA6B,GAEvD,GACF;AAAA,QACA,6CAAC,SAAI,WAAU,kBACb;AAAA,sDAAC,OAAE,eAAW,cAAG,2CAA2C,CAAC,QAAQ,0BAA0B,GAC5F,kBAAQ,aACX;AAAA,UACA,4CAAC,OAAE,WAAU,8CAA8C,mBAAS,IAAI,MAAM,KAAK,WAAU;AAAA,WAC/F;AAAA,SACF;AAAA,MAEC,cACC,4CAAC,OAAE,WAAU,8DAA8D,uBAAY,IACrF;AAAA,MAEJ,6CAAC,SAAI,WAAU,yDACb;AAAA,qDAAC,SACC;AAAA,sDAAC,OAAE,WAAU,0DAAyD,wBAAU;AAAA,UAChF,4CAAC,OAAE,WAAU,YACV,uBAAa,OACZ,6CAAC,aACC;AAAA,wDAAC,qCAAa,QAAQ,aAAa,MAAM,IAAI;AAAA,YAC5C,UAAU,eAAe;AAAA,YAAE;AAAA,YAAE;AAAA,aAChC,IAEA,4CAAC,UAAK,WAAU,yBAAwB,oBAAC,GAE7C;AAAA,WACF;AAAA,QACA,6CAAC,SAAI,WAAU,4EACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,0BAAY;AAAA,UACpD,6CAAC,UAAK,WAAU,6DACd;AAAA,wDAAC,qCAAa,QAAQ,aAAa,MAAM,IAAI;AAAA,YAC5C;AAAA,YAAM;AAAA,YAAE;AAAA,YAAY;AAAA,aACvB;AAAA,WACF;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,eACb;AAAA,qDAAC,SAAI,WAAU,6CACb;AAAA,uDAAC,UAAK,WAAU,+BAA8B;AAAA;AAAA,YAClC;AAAA,YAAQ;AAAA,YAAE,aAAa,OAAO,SAAM,UAAU,eAAe,CAAC,IAAI,UAAU,OAAO,KAAK;AAAA,aACpG;AAAA,UACA,6CAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,YAAW,MAAM;AAAA,YAAQ;AAAA,aAAC;AAAA,WACpE;AAAA,QACA,6CAAC,SAAI,WAAU,kEACZ;AAAA,oBAAU,KAAK,4CAAC,SAAI,OAAO,EAAE,OAAO,GAAG,OAAO,KAAK,YAAY,cAAc,GAAG;AAAA,UACjF,4CAAC,SAAI,WAAU,UAAS;AAAA,WAC1B;AAAA,SACF;AAAA,MAEA,4CAAC,OAAE,WAAU,qCAAoC,kFAEjD;AAAA,OACF;AAAA,KACF;AAEJ;","names":["Image"]}
|
|
@@ -3,11 +3,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import Image from "./image.js";
|
|
4
4
|
import { TrendingUp } from "lucide-react";
|
|
5
5
|
import { cn } from "../utils/cn.js";
|
|
6
|
-
|
|
6
|
+
import { CurrencyIcon } from "./currency-icon.js";
|
|
7
7
|
const COIN_GRADIENT = "linear-gradient(135deg, #f6608f, #fb8b46)";
|
|
8
|
+
function StatValue({ children }) {
|
|
9
|
+
return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1 font-bold tabular-nums text-brand-maeve", children });
|
|
10
|
+
}
|
|
8
11
|
function CoinLaunchPreview({ data, className }) {
|
|
9
|
-
const { name, symbol, description, imageUrl, supplyHuman, quoteSymbol, teamPct } = data;
|
|
10
|
-
const marketCap = supplyHuman != null ? supplyHuman *
|
|
12
|
+
const { name, symbol, description, imageUrl, supplyHuman, price, quoteSymbol, teamPct } = data;
|
|
13
|
+
const marketCap = supplyHuman != null ? supplyHuman * price : null;
|
|
11
14
|
const yourCoins = supplyHuman != null ? supplyHuman * (teamPct / 100) : null;
|
|
12
15
|
return /* @__PURE__ */ jsxs("div", { className: cn("rounded-2xl bg-muted/50 dark:bg-card overflow-hidden", className), children: [
|
|
13
16
|
/* @__PURE__ */ jsx("div", { className: "px-5 pt-4", children: /* @__PURE__ */ jsx("p", { className: "section-label", children: "Live preview" }) }),
|
|
@@ -20,40 +23,44 @@ function CoinLaunchPreview({ data, className }) {
|
|
|
20
23
|
] })
|
|
21
24
|
] }),
|
|
22
25
|
description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-3", children: description }) : null,
|
|
23
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
26
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-xl bg-muted/50 dark:bg-muted/30 p-4 space-y-3", children: [
|
|
24
27
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
25
|
-
/* @__PURE__ */ jsx("p", { className: "text-2xs uppercase tracking-wide text-muted-foreground", children: "
|
|
26
|
-
/* @__PURE__ */
|
|
27
|
-
|
|
28
|
+
/* @__PURE__ */ jsx("p", { className: "text-2xs uppercase tracking-wide text-muted-foreground", children: "Market cap" }),
|
|
29
|
+
/* @__PURE__ */ jsx("p", { className: "text-2xl", children: marketCap != null ? /* @__PURE__ */ jsxs(StatValue, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(CurrencyIcon, { symbol: quoteSymbol, size: 18 }),
|
|
31
|
+
marketCap.toLocaleString(),
|
|
28
32
|
" ",
|
|
29
33
|
quoteSymbol
|
|
30
|
-
] })
|
|
34
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) })
|
|
31
35
|
] }),
|
|
32
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
33
|
-
/* @__PURE__ */ jsx("
|
|
34
|
-
/* @__PURE__ */
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm border-t border-border/60 pt-3", children: [
|
|
37
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Launch price" }),
|
|
38
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 font-semibold tabular-nums", children: [
|
|
39
|
+
/* @__PURE__ */ jsx(CurrencyIcon, { symbol: quoteSymbol, size: 14 }),
|
|
40
|
+
price,
|
|
41
|
+
" ",
|
|
42
|
+
quoteSymbol,
|
|
43
|
+
" / coin"
|
|
44
|
+
] })
|
|
39
45
|
] })
|
|
40
46
|
] }),
|
|
41
47
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
42
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
43
|
-
teamPct > 0 && /* @__PURE__ */ jsx("div", { style: { width: `${teamPct}%`, background: COIN_GRADIENT } }),
|
|
44
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" })
|
|
45
|
-
] }),
|
|
46
|
-
/* @__PURE__ */ jsxs("div", { className: "flex justify-between text-2xs text-muted-foreground", children: [
|
|
48
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
|
|
47
49
|
/* @__PURE__ */ jsxs("span", { className: "font-medium text-brand-rose", children: [
|
|
48
|
-
"You ",
|
|
50
|
+
"You keep ",
|
|
49
51
|
teamPct,
|
|
50
|
-
"%"
|
|
52
|
+
"%",
|
|
53
|
+
yourCoins != null ? ` \xB7 ${yourCoins.toLocaleString()} ${symbol || "coins"}` : ""
|
|
51
54
|
] }),
|
|
52
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
55
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
53
56
|
"Community ",
|
|
54
57
|
100 - teamPct,
|
|
55
58
|
"%"
|
|
56
59
|
] })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-2.5 rounded-full overflow-hidden bg-muted-foreground/15", children: [
|
|
62
|
+
teamPct > 0 && /* @__PURE__ */ jsx("div", { style: { width: `${teamPct}%`, background: COIN_GRADIENT } }),
|
|
63
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" })
|
|
57
64
|
] })
|
|
58
65
|
] }),
|
|
59
66
|
/* @__PURE__ */ jsx("p", { className: "text-2xs text-muted-foreground/70", children: "Liquidity is locked forever \u2014 nobody can pull it, including us." })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/coin-launch-preview.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { TrendingUp } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface CoinPreviewData {\n name: string;\n symbol: string;\n description: string;\n\n imageUrl: string | null;\n\n supplyHuman: number | null;\n quoteSymbol: string;\n teamPct: number;\n}\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-launch-preview.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { TrendingUp } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CurrencyIcon } from \"./currency-icon.js\";\n\nexport interface CoinPreviewData {\n name: string;\n symbol: string;\n description: string;\n\n imageUrl: string | null;\n\n supplyHuman: number | null;\n price: number;\n quoteSymbol: string;\n teamPct: number;\n}\n\nconst COIN_GRADIENT = \"linear-gradient(135deg, #f6608f, #fb8b46)\";\n\nfunction StatValue({ children }: { children: React.ReactNode }) {\n return (\n <span className=\"inline-flex items-center gap-1 font-bold tabular-nums text-brand-maeve\">\n {children}\n </span>\n );\n}\n\nexport function CoinLaunchPreview({ data, className }: { data: CoinPreviewData; className?: string }) {\n const { name, symbol, description, imageUrl, supplyHuman, price, quoteSymbol, teamPct } = data;\n const marketCap = supplyHuman != null ? supplyHuman * price : null;\n const yourCoins = supplyHuman != null ? supplyHuman * (teamPct / 100) : null;\n\n return (\n <div className={cn(\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden\", className)}>\n <div className=\"px-5 pt-4\">\n <p className=\"section-label\">Live preview</p>\n </div>\n\n <div className=\"p-5 space-y-4\">\n\n <div className=\"flex items-center gap-3\">\n <div className=\"shrink-0 rounded-full p-[2px]\" style={{ background: COIN_GRADIENT }}>\n <div className=\"relative h-14 w-14 rounded-full overflow-hidden bg-card flex items-center justify-center\">\n {imageUrl ? (\n <Image src={imageUrl} alt=\"\" fill sizes=\"56px\" className=\"object-cover\" unoptimized />\n ) : (\n <TrendingUp className=\"h-6 w-6 text-brand-rose/70\" />\n )}\n </div>\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className={cn(\"font-bold text-lg leading-snug truncate\", !name && \"text-muted-foreground/50\")}>\n {name || \"Your coin\"}\n </p>\n <p className=\"text-sm text-muted-foreground tabular-nums\">{symbol ? `$${symbol}` : \"$SYMBOL\"}</p>\n </div>\n </div>\n\n {description ? (\n <p className=\"text-sm text-muted-foreground leading-relaxed line-clamp-3\">{description}</p>\n ) : null}\n\n <div className=\"rounded-xl bg-muted/50 dark:bg-muted/30 p-4 space-y-3\">\n <div>\n <p className=\"text-2xs uppercase tracking-wide text-muted-foreground\">Market cap</p>\n <p className=\"text-2xl\">\n {marketCap != null ? (\n <StatValue>\n <CurrencyIcon symbol={quoteSymbol} size={18} />\n {marketCap.toLocaleString()} {quoteSymbol}\n </StatValue>\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n )}\n </p>\n </div>\n <div className=\"flex items-center justify-between text-sm border-t border-border/60 pt-3\">\n <span className=\"text-muted-foreground\">Launch price</span>\n <span className=\"inline-flex items-center gap-1 font-semibold tabular-nums\">\n <CurrencyIcon symbol={quoteSymbol} size={14} />\n {price} {quoteSymbol} / coin\n </span>\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium text-brand-rose\">\n You keep {teamPct}%{yourCoins != null ? ` · ${yourCoins.toLocaleString()} ${symbol || \"coins\"}` : \"\"}\n </span>\n <span className=\"text-muted-foreground\">Community {100 - teamPct}%</span>\n </div>\n <div className=\"flex h-2.5 rounded-full overflow-hidden bg-muted-foreground/15\">\n {teamPct > 0 && <div style={{ width: `${teamPct}%`, background: COIN_GRADIENT }} />}\n <div className=\"flex-1\" />\n </div>\n </div>\n\n <p className=\"text-2xs text-muted-foreground/70\">\n Liquidity is locked forever — nobody can pull it, including us.\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":";AAwBI,cA6BM,YA7BN;AAtBJ,OAAO,WAAW;AAClB,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AACnB,SAAS,oBAAoB;AAe7B,MAAM,gBAAgB;AAEtB,SAAS,UAAU,EAAE,SAAS,GAAkC;AAC9D,SACE,oBAAC,UAAK,WAAU,0EACb,UACH;AAEJ;AAEO,SAAS,kBAAkB,EAAE,MAAM,UAAU,GAAkD;AACpG,QAAM,EAAE,MAAM,QAAQ,aAAa,UAAU,aAAa,OAAO,aAAa,QAAQ,IAAI;AAC1F,QAAM,YAAY,eAAe,OAAO,cAAc,QAAQ;AAC9D,QAAM,YAAY,eAAe,OAAO,eAAe,UAAU,OAAO;AAExE,SACE,qBAAC,SAAI,WAAW,GAAG,wDAAwD,SAAS,GAClF;AAAA,wBAAC,SAAI,WAAU,aACb,8BAAC,OAAE,WAAU,iBAAgB,0BAAY,GAC3C;AAAA,IAEA,qBAAC,SAAI,WAAU,iBAEb;AAAA,2BAAC,SAAI,WAAU,2BACb;AAAA,4BAAC,SAAI,WAAU,iCAAgC,OAAO,EAAE,YAAY,cAAc,GAChF,8BAAC,SAAI,WAAU,4FACZ,qBACC,oBAAC,SAAM,KAAK,UAAU,KAAI,IAAG,MAAI,MAAC,OAAM,QAAO,WAAU,gBAAe,aAAW,MAAC,IAEpF,oBAAC,cAAW,WAAU,8BAA6B,GAEvD,GACF;AAAA,QACA,qBAAC,SAAI,WAAU,kBACb;AAAA,8BAAC,OAAE,WAAW,GAAG,2CAA2C,CAAC,QAAQ,0BAA0B,GAC5F,kBAAQ,aACX;AAAA,UACA,oBAAC,OAAE,WAAU,8CAA8C,mBAAS,IAAI,MAAM,KAAK,WAAU;AAAA,WAC/F;AAAA,SACF;AAAA,MAEC,cACC,oBAAC,OAAE,WAAU,8DAA8D,uBAAY,IACrF;AAAA,MAEJ,qBAAC,SAAI,WAAU,yDACb;AAAA,6BAAC,SACC;AAAA,8BAAC,OAAE,WAAU,0DAAyD,wBAAU;AAAA,UAChF,oBAAC,OAAE,WAAU,YACV,uBAAa,OACZ,qBAAC,aACC;AAAA,gCAAC,gBAAa,QAAQ,aAAa,MAAM,IAAI;AAAA,YAC5C,UAAU,eAAe;AAAA,YAAE;AAAA,YAAE;AAAA,aAChC,IAEA,oBAAC,UAAK,WAAU,yBAAwB,oBAAC,GAE7C;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,4EACb;AAAA,8BAAC,UAAK,WAAU,yBAAwB,0BAAY;AAAA,UACpD,qBAAC,UAAK,WAAU,6DACd;AAAA,gCAAC,gBAAa,QAAQ,aAAa,MAAM,IAAI;AAAA,YAC5C;AAAA,YAAM;AAAA,YAAE;AAAA,YAAY;AAAA,aACvB;AAAA,WACF;AAAA,SACF;AAAA,MAEA,qBAAC,SAAI,WAAU,eACb;AAAA,6BAAC,SAAI,WAAU,6CACb;AAAA,+BAAC,UAAK,WAAU,+BAA8B;AAAA;AAAA,YAClC;AAAA,YAAQ;AAAA,YAAE,aAAa,OAAO,SAAM,UAAU,eAAe,CAAC,IAAI,UAAU,OAAO,KAAK;AAAA,aACpG;AAAA,UACA,qBAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,YAAW,MAAM;AAAA,YAAQ;AAAA,aAAC;AAAA,WACpE;AAAA,QACA,qBAAC,SAAI,WAAU,kEACZ;AAAA,oBAAU,KAAK,oBAAC,SAAI,OAAO,EAAE,OAAO,GAAG,OAAO,KAAK,YAAY,cAAc,GAAG;AAAA,UACjF,oBAAC,SAAI,WAAU,UAAS;AAAA,WAC1B;AAAA,SACF;AAAA,MAEA,oBAAC,OAAE,WAAU,qCAAoC,kFAEjD;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -68,7 +68,14 @@ function CoinAvatar({ collection, size = 36 }) {
|
|
|
68
68
|
function PriceCell({ price, status, isLoading }) {
|
|
69
69
|
if (isLoading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20" });
|
|
70
70
|
if (!price) {
|
|
71
|
-
return status === "pre-launch" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-right text-xs text-muted-foreground", children: "Not trading yet" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
71
|
+
return status === "pre-launch" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-right text-xs text-muted-foreground", children: "Not trading yet" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
72
|
+
"span",
|
|
73
|
+
{
|
|
74
|
+
className: "block text-right text-muted-foreground",
|
|
75
|
+
title: "No liquidity route was found for this coin on any Starknet DEX yet.",
|
|
76
|
+
children: "\u2014"
|
|
77
|
+
}
|
|
78
|
+
);
|
|
72
79
|
}
|
|
73
80
|
const usd = price.quoteUsdRate != null ? (0, import_format.formatUsdPrice)(price.quotePerCoin * price.quoteUsdRate) : null;
|
|
74
81
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -77,7 +84,8 @@ function PriceCell({ price, status, isLoading }) {
|
|
|
77
84
|
amountFormatted: String(price.quotePerCoin),
|
|
78
85
|
currency: price.quoteSymbol,
|
|
79
86
|
usdValue: usd,
|
|
80
|
-
scale: "card"
|
|
87
|
+
scale: "card",
|
|
88
|
+
secondaryClassName: "hidden sm:flex"
|
|
81
89
|
}
|
|
82
90
|
) });
|
|
83
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/coin-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport {\n coinKind, coinKindLabel, coinAccentToken,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\nimport { formatUsdPrice } from \"../utils/format.js\";\n\nexport type CoinMarketStatus = \"live\" | \"pre-launch\" | \"unavailable\";\n\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n status?: CoinMarketStatus;\n isLoading: boolean;\n};\n\nexport const COIN_GRID = \"grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 sm:gap-4\";\n\nexport interface CoinRowProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n href: string;\n showKind?: boolean;\n}\n\nexport function CoinAvatar({ collection, size = 36 }: { collection: CoinCollectionLike; size?: number }) {\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const accent = coinAccentToken(collection.symbol ?? collection.name ?? collection.contractAddress);\n\n return (\n <div\n className={cn(\"relative shrink-0 overflow-hidden rounded-full\", accent)}\n style={{ width: size, height: size }}\n >\n {logo ? (\n <Image src={logo} alt=\"\" fill sizes={`${size}px`} className=\"object-cover\" unoptimized />\n ) : (\n <span\n className=\"flex h-full w-full items-center justify-center font-bold leading-none text-white\"\n style={{ fontSize: size * 0.36 }}\n >\n {initials}\n </span>\n )}\n </div>\n );\n}\n\nfunction PriceCell({ price, status, isLoading }: { price: CoinPriceLike | null; status?: CoinMarketStatus; isLoading: boolean }) {\n if (isLoading) return <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />;\n if (!price) {\n return status === \"pre-launch\" ? (\n <span className=\"block text-right text-xs text-muted-foreground\">Not trading yet</span>\n ) : (\n <span
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport {\n coinKind, coinKindLabel, coinAccentToken,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\nimport { formatUsdPrice } from \"../utils/format.js\";\n\nexport type CoinMarketStatus = \"live\" | \"pre-launch\" | \"unavailable\";\n\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n status?: CoinMarketStatus;\n isLoading: boolean;\n};\n\nexport const COIN_GRID = \"grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 sm:gap-4\";\n\nexport interface CoinRowProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n href: string;\n showKind?: boolean;\n}\n\nexport function CoinAvatar({ collection, size = 36 }: { collection: CoinCollectionLike; size?: number }) {\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const accent = coinAccentToken(collection.symbol ?? collection.name ?? collection.contractAddress);\n\n return (\n <div\n className={cn(\"relative shrink-0 overflow-hidden rounded-full\", accent)}\n style={{ width: size, height: size }}\n >\n {logo ? (\n <Image src={logo} alt=\"\" fill sizes={`${size}px`} className=\"object-cover\" unoptimized />\n ) : (\n <span\n className=\"flex h-full w-full items-center justify-center font-bold leading-none text-white\"\n style={{ fontSize: size * 0.36 }}\n >\n {initials}\n </span>\n )}\n </div>\n );\n}\n\nfunction PriceCell({ price, status, isLoading }: { price: CoinPriceLike | null; status?: CoinMarketStatus; isLoading: boolean }) {\n if (isLoading) return <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />;\n if (!price) {\n return status === \"pre-launch\" ? (\n <span className=\"block text-right text-xs text-muted-foreground\">Not trading yet</span>\n ) : (\n <span\n className=\"block text-right text-muted-foreground\"\n title=\"No liquidity route was found for this coin on any Starknet DEX yet.\"\n >\n —\n </span>\n );\n }\n\n const usd = price.quoteUsdRate != null ? formatUsdPrice(price.quotePerCoin * price.quoteUsdRate) : null;\n\n return (\n <span className=\"flex justify-end\">\n <DualPrice\n amountFormatted={String(price.quotePerCoin)}\n currency={price.quoteSymbol}\n usdValue={usd}\n scale=\"card\"\n secondaryClassName=\"hidden sm:flex\"\n />\n </span>\n );\n}\n\nexport function CoinRow({ collection, usePrice, href, showKind = false }: CoinRowProps) {\n const { price, status, isLoading } = usePrice(collection);\n\n return (\n <Link\n href={href}\n className={cn(\n COIN_GRID,\n \"border-b border-border/40 px-2 py-2.5 text-sm transition-colors\",\n \"hover:bg-muted/40 active:bg-muted/60\"\n )}\n >\n <span className=\"flex min-w-0 items-center gap-3\">\n <CoinAvatar collection={collection} />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-semibold leading-tight\">{collection.name ?? \"Untitled coin\"}</span>\n <span className=\"block truncate text-xs text-muted-foreground\">\n {collection.symbol ?? \"—\"}\n {showKind && <span className=\"text-muted-foreground/60\"> · {coinKindLabel(coinKind(collection.service))}</span>}\n </span>\n </span>\n </span>\n\n <PriceCell price={price} status={status} isLoading={isLoading} />\n </Link>\n );\n}\n\nexport function CoinRowSkeleton() {\n return (\n <div className={cn(COIN_GRID, \"border-b border-border/40 px-2 py-2.5\")}>\n <span className=\"flex items-center gap-3\">\n <span className=\"h-9 w-9 shrink-0 animate-pulse rounded-full bg-muted-foreground/20\" />\n <span className=\"space-y-1.5\">\n <span className=\"block h-4 w-28 animate-pulse rounded bg-muted-foreground/20\" />\n <span className=\"block h-3 w-14 animate-pulse rounded bg-muted-foreground/10\" />\n </span>\n </span>\n <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />\n </div>\n );\n}\n"],"mappings":"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","names":["Image","Link"]}
|
|
@@ -36,7 +36,14 @@ function CoinAvatar({ collection, size = 36 }) {
|
|
|
36
36
|
function PriceCell({ price, status, isLoading }) {
|
|
37
37
|
if (isLoading) return /* @__PURE__ */ jsx("span", { className: "ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20" });
|
|
38
38
|
if (!price) {
|
|
39
|
-
return status === "pre-launch" ? /* @__PURE__ */ jsx("span", { className: "block text-right text-xs text-muted-foreground", children: "Not trading yet" }) : /* @__PURE__ */ jsx(
|
|
39
|
+
return status === "pre-launch" ? /* @__PURE__ */ jsx("span", { className: "block text-right text-xs text-muted-foreground", children: "Not trading yet" }) : /* @__PURE__ */ jsx(
|
|
40
|
+
"span",
|
|
41
|
+
{
|
|
42
|
+
className: "block text-right text-muted-foreground",
|
|
43
|
+
title: "No liquidity route was found for this coin on any Starknet DEX yet.",
|
|
44
|
+
children: "\u2014"
|
|
45
|
+
}
|
|
46
|
+
);
|
|
40
47
|
}
|
|
41
48
|
const usd = price.quoteUsdRate != null ? formatUsdPrice(price.quotePerCoin * price.quoteUsdRate) : null;
|
|
42
49
|
return /* @__PURE__ */ jsx("span", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
|
|
@@ -45,7 +52,8 @@ function PriceCell({ price, status, isLoading }) {
|
|
|
45
52
|
amountFormatted: String(price.quotePerCoin),
|
|
46
53
|
currency: price.quoteSymbol,
|
|
47
54
|
usdValue: usd,
|
|
48
|
-
scale: "card"
|
|
55
|
+
scale: "card",
|
|
56
|
+
secondaryClassName: "hidden sm:flex"
|
|
49
57
|
}
|
|
50
58
|
) });
|
|
51
59
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/coin-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport {\n coinKind, coinKindLabel, coinAccentToken,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\nimport { formatUsdPrice } from \"../utils/format.js\";\n\nexport type CoinMarketStatus = \"live\" | \"pre-launch\" | \"unavailable\";\n\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n status?: CoinMarketStatus;\n isLoading: boolean;\n};\n\nexport const COIN_GRID = \"grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 sm:gap-4\";\n\nexport interface CoinRowProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n href: string;\n showKind?: boolean;\n}\n\nexport function CoinAvatar({ collection, size = 36 }: { collection: CoinCollectionLike; size?: number }) {\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const accent = coinAccentToken(collection.symbol ?? collection.name ?? collection.contractAddress);\n\n return (\n <div\n className={cn(\"relative shrink-0 overflow-hidden rounded-full\", accent)}\n style={{ width: size, height: size }}\n >\n {logo ? (\n <Image src={logo} alt=\"\" fill sizes={`${size}px`} className=\"object-cover\" unoptimized />\n ) : (\n <span\n className=\"flex h-full w-full items-center justify-center font-bold leading-none text-white\"\n style={{ fontSize: size * 0.36 }}\n >\n {initials}\n </span>\n )}\n </div>\n );\n}\n\nfunction PriceCell({ price, status, isLoading }: { price: CoinPriceLike | null; status?: CoinMarketStatus; isLoading: boolean }) {\n if (isLoading) return <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />;\n if (!price) {\n return status === \"pre-launch\" ? (\n <span className=\"block text-right text-xs text-muted-foreground\">Not trading yet</span>\n ) : (\n <span
|
|
1
|
+
{"version":3,"sources":["../../src/components/coin-row.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { ipfsToHttp } from \"../utils/ipfs.js\";\nimport { DualPrice } from \"./dual-price.js\";\nimport {\n coinKind, coinKindLabel, coinAccentToken,\n type CoinCollectionLike, type CoinPriceLike,\n} from \"../data/coins.js\";\nimport { formatUsdPrice } from \"../utils/format.js\";\n\nexport type CoinMarketStatus = \"live\" | \"pre-launch\" | \"unavailable\";\n\nexport type UseCoinPrice = (collection: CoinCollectionLike) => {\n price: CoinPriceLike | null;\n status?: CoinMarketStatus;\n isLoading: boolean;\n};\n\nexport const COIN_GRID = \"grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 sm:gap-4\";\n\nexport interface CoinRowProps {\n collection: CoinCollectionLike;\n usePrice: UseCoinPrice;\n href: string;\n showKind?: boolean;\n}\n\nexport function CoinAvatar({ collection, size = 36 }: { collection: CoinCollectionLike; size?: number }) {\n const logoUri = collection.profile?.image ?? collection.image;\n const logo = logoUri ? ipfsToHttp(logoUri) : null;\n const initials = (collection.symbol ?? collection.name ?? \"?\").trim().slice(0, 2).toUpperCase();\n const accent = coinAccentToken(collection.symbol ?? collection.name ?? collection.contractAddress);\n\n return (\n <div\n className={cn(\"relative shrink-0 overflow-hidden rounded-full\", accent)}\n style={{ width: size, height: size }}\n >\n {logo ? (\n <Image src={logo} alt=\"\" fill sizes={`${size}px`} className=\"object-cover\" unoptimized />\n ) : (\n <span\n className=\"flex h-full w-full items-center justify-center font-bold leading-none text-white\"\n style={{ fontSize: size * 0.36 }}\n >\n {initials}\n </span>\n )}\n </div>\n );\n}\n\nfunction PriceCell({ price, status, isLoading }: { price: CoinPriceLike | null; status?: CoinMarketStatus; isLoading: boolean }) {\n if (isLoading) return <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />;\n if (!price) {\n return status === \"pre-launch\" ? (\n <span className=\"block text-right text-xs text-muted-foreground\">Not trading yet</span>\n ) : (\n <span\n className=\"block text-right text-muted-foreground\"\n title=\"No liquidity route was found for this coin on any Starknet DEX yet.\"\n >\n —\n </span>\n );\n }\n\n const usd = price.quoteUsdRate != null ? formatUsdPrice(price.quotePerCoin * price.quoteUsdRate) : null;\n\n return (\n <span className=\"flex justify-end\">\n <DualPrice\n amountFormatted={String(price.quotePerCoin)}\n currency={price.quoteSymbol}\n usdValue={usd}\n scale=\"card\"\n secondaryClassName=\"hidden sm:flex\"\n />\n </span>\n );\n}\n\nexport function CoinRow({ collection, usePrice, href, showKind = false }: CoinRowProps) {\n const { price, status, isLoading } = usePrice(collection);\n\n return (\n <Link\n href={href}\n className={cn(\n COIN_GRID,\n \"border-b border-border/40 px-2 py-2.5 text-sm transition-colors\",\n \"hover:bg-muted/40 active:bg-muted/60\"\n )}\n >\n <span className=\"flex min-w-0 items-center gap-3\">\n <CoinAvatar collection={collection} />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-semibold leading-tight\">{collection.name ?? \"Untitled coin\"}</span>\n <span className=\"block truncate text-xs text-muted-foreground\">\n {collection.symbol ?? \"—\"}\n {showKind && <span className=\"text-muted-foreground/60\"> · {coinKindLabel(coinKind(collection.service))}</span>}\n </span>\n </span>\n </span>\n\n <PriceCell price={price} status={status} isLoading={isLoading} />\n </Link>\n );\n}\n\nexport function CoinRowSkeleton() {\n return (\n <div className={cn(COIN_GRID, \"border-b border-border/40 px-2 py-2.5\")}>\n <span className=\"flex items-center gap-3\">\n <span className=\"h-9 w-9 shrink-0 animate-pulse rounded-full bg-muted-foreground/20\" />\n <span className=\"space-y-1.5\">\n <span className=\"block h-4 w-28 animate-pulse rounded bg-muted-foreground/20\" />\n <span className=\"block h-3 w-14 animate-pulse rounded bg-muted-foreground/10\" />\n </span>\n </span>\n <span className=\"ml-auto block h-4 w-16 animate-pulse rounded bg-muted-foreground/20\" />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -28,54 +28,52 @@ var import_lucide_react = require("lucide-react");
|
|
|
28
28
|
var import_cn = require("../utils/cn.js");
|
|
29
29
|
var import_coin_row = require("./coin-row.js");
|
|
30
30
|
var import_stat_tile = require("./stat-tile.js");
|
|
31
|
+
var import_coin_order = require("../data/coin-order.js");
|
|
31
32
|
var import_coins = require("../data/coins.js");
|
|
32
|
-
const FILTER_TABS = [
|
|
33
|
-
{ label: "All", value: "all" },
|
|
34
|
-
...import_coins.COIN_KINDS.map((kind) => ({ label: (0, import_coins.coinKindLabel)(kind), value: kind }))
|
|
35
|
-
];
|
|
36
33
|
const SORT_OPTIONS = [
|
|
37
34
|
{ label: "Recently launched", value: "recent" },
|
|
38
35
|
{ label: "Name", value: "name" }
|
|
39
36
|
];
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action }) {
|
|
37
|
+
const noPriceMap = () => ({ prices: {}, isLoading: false });
|
|
38
|
+
function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }) {
|
|
43
39
|
const [filter, setFilter] = (0, import_react.useState)("all");
|
|
44
40
|
const [sort, setSort] = (0, import_react.useState)("recent");
|
|
45
41
|
const [query, setQuery] = (0, import_react.useState)("");
|
|
46
|
-
const [
|
|
47
|
-
const filterCount = (filter !== "all" ? 1 : 0) + (sort !== "recent" ? 1 : 0);
|
|
48
|
-
(0, import_react.useEffect)(() => {
|
|
49
|
-
if (!filtersOpen) return;
|
|
50
|
-
const onKey = (e) => e.key === "Escape" && setFiltersOpen(false);
|
|
51
|
-
window.addEventListener("keydown", onKey);
|
|
52
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
53
|
-
}, [filtersOpen]);
|
|
42
|
+
const [priceSort, setPriceSort] = (0, import_react.useState)(void 0);
|
|
54
43
|
const { collections, isLoading, counts } = useCoins({ filter, sort });
|
|
44
|
+
const { prices } = (usePriceMap ?? noPriceMap)();
|
|
55
45
|
const items = (0, import_react.useMemo)(() => {
|
|
56
46
|
const q = query.trim().toLowerCase();
|
|
57
|
-
|
|
58
|
-
return
|
|
59
|
-
|
|
60
|
-
);
|
|
61
|
-
}, [collections, query]);
|
|
47
|
+
const matched = q ? collections.filter((c) => (c.name ?? "").toLowerCase().includes(q) || (c.symbol ?? "").toLowerCase().includes(q)) : collections;
|
|
48
|
+
return usePriceMap ? (0, import_coin_order.orderCoins)(matched, prices, priceSort) : matched;
|
|
49
|
+
}, [collections, query, usePriceMap, prices, priceSort]);
|
|
62
50
|
const showKind = (0, import_react.useMemo)(() => new Set(items.map((c) => (0, import_coins.coinKind)(c.service))).size > 1, [items]);
|
|
63
|
-
const statItems = (0, import_react.useMemo)(() => {
|
|
64
|
-
if (!counts) return [];
|
|
51
|
+
const { statItems, pillFilters } = (0, import_react.useMemo)(() => {
|
|
52
|
+
if (!counts) return { statItems: [], pillFilters: [] };
|
|
65
53
|
const forKind = (kind) => (0, import_coins.coinServiceIds)(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);
|
|
66
54
|
const total = Object.values(counts).reduce((a, b) => a + b, 0);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
55
|
+
const kinds = import_coins.COIN_KINDS.filter((kind) => forKind(kind) > 0);
|
|
56
|
+
return {
|
|
57
|
+
statItems: [
|
|
58
|
+
{ label: total === 1 ? "Coin" : "Coins", value: total },
|
|
59
|
+
...kinds.map((kind) => ({ label: (0, import_coins.coinKindLabelPlural)(kind), value: forKind(kind) }))
|
|
60
|
+
],
|
|
61
|
+
pillFilters: ["all", ...kinds]
|
|
62
|
+
};
|
|
73
63
|
}, [counts]);
|
|
64
|
+
const activeIndex = pillFilters.indexOf(filter);
|
|
74
65
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-5", children: [
|
|
75
66
|
heading && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
|
|
76
67
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
77
68
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" }),
|
|
78
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
69
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
70
|
+
import_stat_tile.StatPillRow,
|
|
71
|
+
{
|
|
72
|
+
items: statItems,
|
|
73
|
+
onSelect: (index) => setFilter(pillFilters[index]),
|
|
74
|
+
activeIndex
|
|
75
|
+
}
|
|
76
|
+
)
|
|
79
77
|
] }),
|
|
80
78
|
action
|
|
81
79
|
] }),
|
|
@@ -92,27 +90,32 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action })
|
|
|
92
90
|
}
|
|
93
91
|
)
|
|
94
92
|
] }),
|
|
95
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
96
|
-
"
|
|
93
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
94
|
+
"select",
|
|
97
95
|
{
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
filterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-2xs font-semibold text-primary-foreground", children: filterCount })
|
|
104
|
-
]
|
|
96
|
+
value: sort,
|
|
97
|
+
onChange: (e) => setSort(e.target.value),
|
|
98
|
+
"aria-label": "Sort coins",
|
|
99
|
+
className: "shrink-0 rounded-lg border border-border bg-background px-2.5 py-2 text-xs font-medium text-foreground outline-none focus:border-primary/50",
|
|
100
|
+
children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value, children: label }, value))
|
|
105
101
|
}
|
|
106
102
|
)
|
|
107
103
|
] }),
|
|
108
|
-
filterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
109
|
-
filter !== "all" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, { onClear: () => setFilter("all"), children: filterLabel(filter) }),
|
|
110
|
-
sort !== "recent" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, { onClear: () => setSort("recent"), children: sortLabel(sort) })
|
|
111
|
-
] }),
|
|
112
104
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
113
105
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)(import_coin_row.COIN_GRID, "border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground"), children: [
|
|
114
106
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Token" }),
|
|
115
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
107
|
+
usePriceMap ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
108
|
+
"button",
|
|
109
|
+
{
|
|
110
|
+
type: "button",
|
|
111
|
+
onClick: () => setPriceSort(priceSort === void 0 ? "desc" : priceSort === "desc" ? "asc" : void 0),
|
|
112
|
+
className: (0, import_cn.cn)("text-right uppercase tracking-wide", priceSort ? "text-foreground" : "text-muted-foreground"),
|
|
113
|
+
children: [
|
|
114
|
+
"Price",
|
|
115
|
+
priceSort === "desc" ? " \u2193" : priceSort === "asc" ? " \u2191" : ""
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-right", children: "Price" })
|
|
116
119
|
] }),
|
|
117
120
|
isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_row.CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "py-16 text-center text-sm text-muted-foreground", children: query.trim() ? `No coins match "${query.trim()}".` : "No coins yet." }) : items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
118
121
|
import_coin_row.CoinRow,
|
|
@@ -124,71 +127,9 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action })
|
|
|
124
127
|
},
|
|
125
128
|
`${c.chain}-${c.contractAddress}`
|
|
126
129
|
))
|
|
127
|
-
] }),
|
|
128
|
-
filtersOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", role: "dialog", "aria-modal": "true", "aria-label": "Filters", children: [
|
|
129
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 bg-background/70 backdrop-blur-sm", onClick: () => setFiltersOpen(false) }),
|
|
130
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative z-10 w-full max-w-sm space-y-5 overflow-hidden rounded-[calc(var(--radius)*1.25)] bg-card p-5", children: [
|
|
131
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
132
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h2", { className: "flex items-center gap-2 text-base font-bold", children: [
|
|
133
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.SlidersHorizontal, { className: "h-4 w-4 text-primary" }),
|
|
134
|
-
"Filters"
|
|
135
|
-
] }),
|
|
136
|
-
filterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
137
|
-
"button",
|
|
138
|
-
{
|
|
139
|
-
onClick: () => {
|
|
140
|
-
setFilter("all");
|
|
141
|
-
setSort("recent");
|
|
142
|
-
},
|
|
143
|
-
className: "text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
144
|
-
children: "Clear all"
|
|
145
|
-
}
|
|
146
|
-
)
|
|
147
|
-
] }),
|
|
148
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterGroup, { label: "Type", children: FILTER_TABS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PillButton, { active: filter === value, onClick: () => setFilter(value), children: label }, value)) }),
|
|
149
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterGroup, { label: "Sort", children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PillButton, { active: sort === value, onClick: () => setSort(value), children: label }, value)) }),
|
|
150
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
151
|
-
"button",
|
|
152
|
-
{
|
|
153
|
-
onClick: () => setFiltersOpen(false),
|
|
154
|
-
className: "w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white",
|
|
155
|
-
children: [
|
|
156
|
-
"Show ",
|
|
157
|
-
items.length,
|
|
158
|
-
" ",
|
|
159
|
-
items.length === 1 ? "coin" : "coins"
|
|
160
|
-
]
|
|
161
|
-
}
|
|
162
|
-
)
|
|
163
|
-
] })
|
|
164
130
|
] })
|
|
165
131
|
] });
|
|
166
132
|
}
|
|
167
|
-
function FilterGroup({ label, children }) {
|
|
168
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
169
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs font-medium text-muted-foreground", children: label }),
|
|
170
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-1.5", children })
|
|
171
|
-
] });
|
|
172
|
-
}
|
|
173
|
-
function PillButton({ active, onClick, children }) {
|
|
174
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
175
|
-
"button",
|
|
176
|
-
{
|
|
177
|
-
onClick,
|
|
178
|
-
className: (0, import_cn.cn)(
|
|
179
|
-
"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
180
|
-
active ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
|
|
181
|
-
),
|
|
182
|
-
children
|
|
183
|
-
}
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
function Chip({ children, onClear }) {
|
|
187
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary", children: [
|
|
188
|
-
children,
|
|
189
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: onClear, "aria-label": "Clear filter", className: "hover:text-primary/60", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-3 w-3" }) })
|
|
190
|
-
] });
|
|
191
|
-
}
|
|
192
133
|
// Annotate the CommonJS export names for ESM import in node:
|
|
193
134
|
0 && (module.exports = {
|
|
194
135
|
CoinsExplorer
|