@medialane/ui 0.137.1 → 0.138.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-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/data/drop-create-schema.d.cts +2 -2
- package/dist/data/drop-create-schema.d.ts +2 -2
- 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
|
@@ -1,58 +1,56 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useMemo
|
|
4
|
-
import { Search
|
|
3
|
+
import { useState, useMemo } from "react";
|
|
4
|
+
import { Search } from "lucide-react";
|
|
5
5
|
import { cn } from "../utils/cn.js";
|
|
6
6
|
import { CoinRow, CoinRowSkeleton, COIN_GRID } from "./coin-row.js";
|
|
7
7
|
import { StatPillRow } from "./stat-tile.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
{ label: "All", value: "all" },
|
|
11
|
-
...COIN_KINDS.map((kind) => ({ label: coinKindLabel(kind), value: kind }))
|
|
12
|
-
];
|
|
8
|
+
import { orderCoins } from "../data/coin-order.js";
|
|
9
|
+
import { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS } from "../data/coins.js";
|
|
13
10
|
const SORT_OPTIONS = [
|
|
14
11
|
{ label: "Recently launched", value: "recent" },
|
|
15
12
|
{ label: "Name", value: "name" }
|
|
16
13
|
];
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action }) {
|
|
14
|
+
const noPriceMap = () => ({ prices: {}, isLoading: false });
|
|
15
|
+
function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }) {
|
|
20
16
|
const [filter, setFilter] = useState("all");
|
|
21
17
|
const [sort, setSort] = useState("recent");
|
|
22
18
|
const [query, setQuery] = useState("");
|
|
23
|
-
const [
|
|
24
|
-
const filterCount = (filter !== "all" ? 1 : 0) + (sort !== "recent" ? 1 : 0);
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (!filtersOpen) return;
|
|
27
|
-
const onKey = (e) => e.key === "Escape" && setFiltersOpen(false);
|
|
28
|
-
window.addEventListener("keydown", onKey);
|
|
29
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
30
|
-
}, [filtersOpen]);
|
|
19
|
+
const [priceSort, setPriceSort] = useState(void 0);
|
|
31
20
|
const { collections, isLoading, counts } = useCoins({ filter, sort });
|
|
21
|
+
const { prices } = (usePriceMap ?? noPriceMap)();
|
|
32
22
|
const items = useMemo(() => {
|
|
33
23
|
const q = query.trim().toLowerCase();
|
|
34
|
-
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
}, [collections, query]);
|
|
24
|
+
const matched = q ? collections.filter((c) => (c.name ?? "").toLowerCase().includes(q) || (c.symbol ?? "").toLowerCase().includes(q)) : collections;
|
|
25
|
+
return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;
|
|
26
|
+
}, [collections, query, usePriceMap, prices, priceSort]);
|
|
39
27
|
const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);
|
|
40
|
-
const statItems = useMemo(() => {
|
|
41
|
-
if (!counts) return [];
|
|
28
|
+
const { statItems, pillFilters } = useMemo(() => {
|
|
29
|
+
if (!counts) return { statItems: [], pillFilters: [] };
|
|
42
30
|
const forKind = (kind) => coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);
|
|
43
31
|
const total = Object.values(counts).reduce((a, b) => a + b, 0);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);
|
|
33
|
+
return {
|
|
34
|
+
statItems: [
|
|
35
|
+
{ label: total === 1 ? "Coin" : "Coins", value: total },
|
|
36
|
+
...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) }))
|
|
37
|
+
],
|
|
38
|
+
pillFilters: ["all", ...kinds]
|
|
39
|
+
};
|
|
50
40
|
}, [counts]);
|
|
41
|
+
const activeIndex = pillFilters.indexOf(filter);
|
|
51
42
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
52
43
|
heading && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
|
|
53
44
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
54
45
|
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold", children: "Creator coins & memecoins" }),
|
|
55
|
-
/* @__PURE__ */ jsx(
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
StatPillRow,
|
|
48
|
+
{
|
|
49
|
+
items: statItems,
|
|
50
|
+
onSelect: (index) => setFilter(pillFilters[index]),
|
|
51
|
+
activeIndex
|
|
52
|
+
}
|
|
53
|
+
)
|
|
56
54
|
] }),
|
|
57
55
|
action
|
|
58
56
|
] }),
|
|
@@ -69,27 +67,32 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action })
|
|
|
69
67
|
}
|
|
70
68
|
)
|
|
71
69
|
] }),
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
"
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"select",
|
|
74
72
|
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
filterCount > 0 && /* @__PURE__ */ 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 })
|
|
81
|
-
]
|
|
73
|
+
value: sort,
|
|
74
|
+
onChange: (e) => setSort(e.target.value),
|
|
75
|
+
"aria-label": "Sort coins",
|
|
76
|
+
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",
|
|
77
|
+
children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ jsx("option", { value, children: label }, value))
|
|
82
78
|
}
|
|
83
79
|
)
|
|
84
80
|
] }),
|
|
85
|
-
filterCount > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
86
|
-
filter !== "all" && /* @__PURE__ */ jsx(Chip, { onClear: () => setFilter("all"), children: filterLabel(filter) }),
|
|
87
|
-
sort !== "recent" && /* @__PURE__ */ jsx(Chip, { onClear: () => setSort("recent"), children: sortLabel(sort) })
|
|
88
|
-
] }),
|
|
89
81
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
90
82
|
/* @__PURE__ */ jsxs("div", { className: cn(COIN_GRID, "border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground"), children: [
|
|
91
83
|
/* @__PURE__ */ jsx("span", { children: "Token" }),
|
|
92
|
-
/* @__PURE__ */
|
|
84
|
+
usePriceMap ? /* @__PURE__ */ jsxs(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
type: "button",
|
|
88
|
+
onClick: () => setPriceSort(priceSort === void 0 ? "desc" : priceSort === "desc" ? "asc" : void 0),
|
|
89
|
+
className: cn("text-right uppercase tracking-wide", priceSort ? "text-foreground" : "text-muted-foreground"),
|
|
90
|
+
children: [
|
|
91
|
+
"Price",
|
|
92
|
+
priceSort === "desc" ? " \u2193" : priceSort === "asc" ? " \u2191" : ""
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
) : /* @__PURE__ */ jsx("span", { className: "text-right", children: "Price" })
|
|
93
96
|
] }),
|
|
94
97
|
isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ 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__ */ jsx(
|
|
95
98
|
CoinRow,
|
|
@@ -101,71 +104,9 @@ function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action })
|
|
|
101
104
|
},
|
|
102
105
|
`${c.chain}-${c.contractAddress}`
|
|
103
106
|
))
|
|
104
|
-
] }),
|
|
105
|
-
filtersOpen && /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", role: "dialog", "aria-modal": "true", "aria-label": "Filters", children: [
|
|
106
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/70 backdrop-blur-sm", onClick: () => setFiltersOpen(false) }),
|
|
107
|
-
/* @__PURE__ */ 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: [
|
|
108
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
109
|
-
/* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-base font-bold", children: [
|
|
110
|
-
/* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-4 w-4 text-primary" }),
|
|
111
|
-
"Filters"
|
|
112
|
-
] }),
|
|
113
|
-
filterCount > 0 && /* @__PURE__ */ jsx(
|
|
114
|
-
"button",
|
|
115
|
-
{
|
|
116
|
-
onClick: () => {
|
|
117
|
-
setFilter("all");
|
|
118
|
-
setSort("recent");
|
|
119
|
-
},
|
|
120
|
-
className: "text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
121
|
-
children: "Clear all"
|
|
122
|
-
}
|
|
123
|
-
)
|
|
124
|
-
] }),
|
|
125
|
-
/* @__PURE__ */ jsx(FilterGroup, { label: "Type", children: FILTER_TABS.map(({ label, value }) => /* @__PURE__ */ jsx(PillButton, { active: filter === value, onClick: () => setFilter(value), children: label }, value)) }),
|
|
126
|
-
/* @__PURE__ */ jsx(FilterGroup, { label: "Sort", children: SORT_OPTIONS.map(({ label, value }) => /* @__PURE__ */ jsx(PillButton, { active: sort === value, onClick: () => setSort(value), children: label }, value)) }),
|
|
127
|
-
/* @__PURE__ */ jsxs(
|
|
128
|
-
"button",
|
|
129
|
-
{
|
|
130
|
-
onClick: () => setFiltersOpen(false),
|
|
131
|
-
className: "w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white",
|
|
132
|
-
children: [
|
|
133
|
-
"Show ",
|
|
134
|
-
items.length,
|
|
135
|
-
" ",
|
|
136
|
-
items.length === 1 ? "coin" : "coins"
|
|
137
|
-
]
|
|
138
|
-
}
|
|
139
|
-
)
|
|
140
|
-
] })
|
|
141
107
|
] })
|
|
142
108
|
] });
|
|
143
109
|
}
|
|
144
|
-
function FilterGroup({ label, children }) {
|
|
145
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
146
|
-
/* @__PURE__ */ jsx("p", { className: "text-2xs font-medium text-muted-foreground", children: label }),
|
|
147
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children })
|
|
148
|
-
] });
|
|
149
|
-
}
|
|
150
|
-
function PillButton({ active, onClick, children }) {
|
|
151
|
-
return /* @__PURE__ */ jsx(
|
|
152
|
-
"button",
|
|
153
|
-
{
|
|
154
|
-
onClick,
|
|
155
|
-
className: cn(
|
|
156
|
-
"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
157
|
-
active ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
|
|
158
|
-
),
|
|
159
|
-
children
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
function Chip({ children, onClear }) {
|
|
164
|
-
return /* @__PURE__ */ 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: [
|
|
165
|
-
children,
|
|
166
|
-
/* @__PURE__ */ jsx("button", { onClick: onClear, "aria-label": "Clear filter", className: "hover:text-primary/60", children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" }) })
|
|
167
|
-
] });
|
|
168
|
-
}
|
|
169
110
|
export {
|
|
170
111
|
CoinsExplorer
|
|
171
112
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo, useEffect } from \"react\";\nimport { Search, SlidersHorizontal, X } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { coinKind, coinKindLabel, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst FILTER_TABS: { label: string; value: CoinFilter }[] = [\n { label: \"All\", value: \"all\" },\n ...COIN_KINDS.map((kind) => ({ label: coinKindLabel(kind), value: kind as CoinFilter })),\n];\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst filterLabel = (v: CoinFilter) => FILTER_TABS.find((t) => t.value === v)?.label ?? \"\";\nconst sortLabel = (v: CoinSort) => SORT_OPTIONS.find((o) => o.value === v)?.label ?? \"\";\n\nexport function CoinsExplorer({ useCoins, usePrice, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [filtersOpen, setFiltersOpen] = useState(false);\n\n const filterCount = (filter !== \"all\" ? 1 : 0) + (sort !== \"recent\" ? 1 : 0);\n\n useEffect(() => {\n if (!filtersOpen) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setFiltersOpen(false);\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [filtersOpen]);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return collections;\n return collections.filter(\n (c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q)\n );\n }, [collections, query]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const statItems = useMemo(() => {\n if (!counts) return [];\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n return [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...COIN_KINDS.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })).filter(\n (s) => s.value > 0,\n ),\n ];\n }, [counts]);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins & memecoins</h1>\n <StatPillRow items={statItems} />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <button\n onClick={() => setFiltersOpen(true)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-2 text-xs font-medium text-foreground hover:border-primary/50\"\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {filterCount > 0 && (\n <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\">\n {filterCount}\n </span>\n )}\n </button>\n </div>\n\n {filterCount > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\">\n {filter !== \"all\" && <Chip onClear={() => setFilter(\"all\")}>{filterLabel(filter)}</Chip>}\n {sort !== \"recent\" && <Chip onClear={() => setSort(\"recent\")}>{sortLabel(sort)}</Chip>}\n </div>\n )}\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n <span className=\"text-right\">Price</span>\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </p>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n\n {filtersOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Filters\">\n <div className=\"absolute inset-0 bg-background/70 backdrop-blur-sm\" onClick={() => setFiltersOpen(false)} />\n <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\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-base font-bold\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </h2>\n {filterCount > 0 && (\n <button\n onClick={() => { setFilter(\"all\"); setSort(\"recent\"); }}\n className=\"text-xs font-medium text-muted-foreground hover:text-foreground\"\n >\n Clear all\n </button>\n )}\n </div>\n\n <FilterGroup label=\"Type\">\n {FILTER_TABS.map(({ label, value }) => (\n <PillButton key={value} active={filter === value} onClick={() => setFilter(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <FilterGroup label=\"Sort\">\n {SORT_OPTIONS.map(({ label, value }) => (\n <PillButton key={value} active={sort === value} onClick={() => setSort(value)}>{label}</PillButton>\n ))}\n </FilterGroup>\n\n <button\n onClick={() => setFiltersOpen(false)}\n className=\"w-full rounded-lg bg-gradient-to-r from-brand-blue to-brand-purple py-2.5 text-sm font-semibold text-white\"\n >\n Show {items.length} {items.length === 1 ? \"coin\" : \"coins\"}\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction FilterGroup({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-medium text-muted-foreground\">{label}</p>\n <div className=\"flex flex-wrap gap-1.5\">{children}</div>\n </div>\n );\n}\n\nfunction PillButton({ active, onClick, children }: { active: boolean; onClick: () => void; children: React.ReactNode }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors\",\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n {children}\n </button>\n );\n}\n\nfunction Chip({ children, onClear }: { children: React.ReactNode; onClear: () => void }) {\n return (\n <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\">\n {children}\n <button onClick={onClear} aria-label=\"Clear filter\" className=\"hover:text-primary/60\">\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { orderCoins, type CoinPriceSort } from \"../data/coin-order.js\";\nimport { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport type UsePriceMap = () => { prices: Record<string, number | null>; isLoading: boolean };\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n usePriceMap?: UsePriceMap;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst noPriceMap: UsePriceMap = () => ({ prices: {}, isLoading: false });\n\nexport function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [priceSort, setPriceSort] = useState<CoinPriceSort | undefined>(undefined);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const { prices } = (usePriceMap ?? noPriceMap)();\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n const matched = q\n ? collections.filter((c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q))\n : collections;\n return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;\n }, [collections, query, usePriceMap, prices, priceSort]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const { statItems, pillFilters } = useMemo(() => {\n if (!counts) return { statItems: [], pillFilters: [] as CoinFilter[] };\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);\n return {\n statItems: [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })),\n ],\n pillFilters: [\"all\", ...kinds] as CoinFilter[],\n };\n }, [counts]);\n\n const activeIndex = pillFilters.indexOf(filter);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins & memecoins</h1>\n <StatPillRow\n items={statItems}\n onSelect={(index) => setFilter(pillFilters[index])}\n activeIndex={activeIndex}\n />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n aria-label=\"Sort coins\"\n 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\"\n >\n {SORT_OPTIONS.map(({ label, value }) => (\n <option key={value} value={value}>{label}</option>\n ))}\n </select>\n </div>\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n {usePriceMap ? (\n <button\n type=\"button\"\n onClick={() => setPriceSort(priceSort === undefined ? \"desc\" : priceSort === \"desc\" ? \"asc\" : undefined)}\n className={cn(\"text-right uppercase tracking-wide\", priceSort ? \"text-foreground\" : \"text-muted-foreground\")}\n >\n Price{priceSort === \"desc\" ? \" ↓\" : priceSort === \"asc\" ? \" ↑\" : \"\"}\n </button>\n ) : (\n <span className=\"text-right\">Price</span>\n )}\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </p>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -74,7 +74,8 @@ function DualPrice({
|
|
|
74
74
|
currency,
|
|
75
75
|
usdValue,
|
|
76
76
|
scale,
|
|
77
|
-
trailing
|
|
77
|
+
trailing,
|
|
78
|
+
secondaryClassName
|
|
78
79
|
}) {
|
|
79
80
|
if (!amountFormatted) return null;
|
|
80
81
|
const s = DUAL_PRICE_SCALES[scale];
|
|
@@ -105,19 +106,21 @@ function DualPrice({
|
|
|
105
106
|
amountClassName: amountClass
|
|
106
107
|
}
|
|
107
108
|
),
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
109
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: `items-center gap-2.5 ${secondaryClassName ?? "flex"}`, children: [
|
|
110
|
+
!stable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${s.divider} w-px bg-border/60 shrink-0` }),
|
|
111
|
+
stable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
112
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: s.stableChip }),
|
|
113
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold text-muted-foreground", children: currency })
|
|
114
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
115
|
+
PriceUnit,
|
|
116
|
+
{
|
|
117
|
+
chip: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinChip, { symbol: currency, size: s.chip }),
|
|
118
|
+
amount: cryptoDisplay,
|
|
119
|
+
label: s.showLabel ? currency ?? void 0 : void 0,
|
|
120
|
+
amountClassName: amountClass
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
] }),
|
|
121
124
|
trailing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-0.5", children: trailing })
|
|
122
125
|
] });
|
|
123
126
|
}
|
|
@@ -1 +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\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\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\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 const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\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 <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n
|
|
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\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\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\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 secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\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 <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n /** Same solid color as the primary USD figure — for cards that want a\n * single consistent shade instead of a muted secondary currency. */\n solid: { dot: \"text-foreground/40\", text: \"text-foreground\" },\n} as const;\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 {stripDollarSign(usdValue)}\n <span className={`font-semibold ${t.text}`}>USD</span>\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":[]}
|
|
@@ -21,12 +21,13 @@ declare const DUAL_PRICE_SCALES: {
|
|
|
21
21
|
readonly showLabel: false;
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
-
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, }: {
|
|
24
|
+
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, secondaryClassName, }: {
|
|
25
25
|
amountFormatted: string | null | undefined;
|
|
26
26
|
currency: string | null | undefined;
|
|
27
27
|
usdValue?: string | null;
|
|
28
28
|
scale: keyof typeof DUAL_PRICE_SCALES;
|
|
29
29
|
trailing?: ReactNode;
|
|
30
|
+
secondaryClassName?: string;
|
|
30
31
|
}): react_jsx_runtime.JSX.Element | null;
|
|
31
32
|
declare const CHIP_TONES: {
|
|
32
33
|
readonly "overlay-dark": {
|
|
@@ -21,12 +21,13 @@ declare const DUAL_PRICE_SCALES: {
|
|
|
21
21
|
readonly showLabel: false;
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
-
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, }: {
|
|
24
|
+
declare function DualPrice({ amountFormatted, currency, usdValue, scale, trailing, secondaryClassName, }: {
|
|
25
25
|
amountFormatted: string | null | undefined;
|
|
26
26
|
currency: string | null | undefined;
|
|
27
27
|
usdValue?: string | null;
|
|
28
28
|
scale: keyof typeof DUAL_PRICE_SCALES;
|
|
29
29
|
trailing?: ReactNode;
|
|
30
|
+
secondaryClassName?: string;
|
|
30
31
|
}): react_jsx_runtime.JSX.Element | null;
|
|
31
32
|
declare const CHIP_TONES: {
|
|
32
33
|
readonly "overlay-dark": {
|
|
@@ -49,7 +49,8 @@ function DualPrice({
|
|
|
49
49
|
currency,
|
|
50
50
|
usdValue,
|
|
51
51
|
scale,
|
|
52
|
-
trailing
|
|
52
|
+
trailing,
|
|
53
|
+
secondaryClassName
|
|
53
54
|
}) {
|
|
54
55
|
if (!amountFormatted) return null;
|
|
55
56
|
const s = DUAL_PRICE_SCALES[scale];
|
|
@@ -80,19 +81,21 @@ function DualPrice({
|
|
|
80
81
|
amountClassName: amountClass
|
|
81
82
|
}
|
|
82
83
|
),
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/* @__PURE__ */
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
84
|
+
/* @__PURE__ */ jsxs("span", { className: `items-center gap-2.5 ${secondaryClassName ?? "flex"}`, children: [
|
|
85
|
+
!stable && /* @__PURE__ */ jsx("span", { className: `${s.divider} w-px bg-border/60 shrink-0` }),
|
|
86
|
+
stable ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
87
|
+
/* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: s.stableChip }),
|
|
88
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-muted-foreground", children: currency })
|
|
89
|
+
] }) : /* @__PURE__ */ jsx(
|
|
90
|
+
PriceUnit,
|
|
91
|
+
{
|
|
92
|
+
chip: /* @__PURE__ */ jsx(CoinChip, { symbol: currency, size: s.chip }),
|
|
93
|
+
amount: cryptoDisplay,
|
|
94
|
+
label: s.showLabel ? currency ?? void 0 : void 0,
|
|
95
|
+
amountClassName: amountClass
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
] }),
|
|
96
99
|
trailing && /* @__PURE__ */ jsx("span", { className: "ml-0.5", children: trailing })
|
|
97
100
|
] });
|
|
98
101
|
}
|
|
@@ -1 +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\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\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\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 const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\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 <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n
|
|
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\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\nfunction FiatChip({ size }: { size: number }) {\n return (\n <span\n className=\"grid shrink-0 place-items-center rounded-full bg-foreground/[0.06] font-extrabold leading-none text-foreground/80\"\n style={{ width: size + 10, height: size + 10, fontSize: size }}\n >\n $\n </span>\n );\n}\n\nfunction stripDollarSign(usdValue: string): string {\n return usdValue.replace(\"$\", \"\");\n}\n\nconst DISPLAY_FACE = \"font-extrabold tracking-tight tabular-nums\";\n\nconst DUAL_PRICE_SCALES = {\n\n hero: { amount: \"text-3xl\", chip: 18, stableChip: 14, divider: \"h-7\", showLabel: true },\n\n card: { amount: \"text-base\", chip: 13, stableChip: 10, divider: \"h-4\", showLabel: false },\n} as const;\n\nfunction PriceUnit({\n chip,\n amount,\n label,\n amountClassName,\n}: {\n chip: ReactNode;\n amount: string;\n label?: string;\n amountClassName: string;\n}) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n {chip}\n <span className=\"flex items-baseline gap-1.5\">\n <span className={amountClassName}>{amount}</span>\n {label && <span className=\"text-sm font-semibold text-muted-foreground/70\">{label}</span>}\n </span>\n </span>\n );\n}\n\nexport function DualPrice({\n amountFormatted,\n currency,\n usdValue,\n scale,\n trailing,\n secondaryClassName,\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 secondaryClassName?: string;\n}) {\n if (!amountFormatted) return null;\n const s = DUAL_PRICE_SCALES[scale];\n const cryptoDisplay = formatDisplayPrice(amountFormatted);\n const amountClass = `${DISPLAY_FACE} ${s.amount}`;\n\n if (!usdValue) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\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 <PriceUnit\n chip={<FiatChip size={s.chip} />}\n amount={stripDollarSign(usdValue)}\n label={s.showLabel ? \"USD\" : undefined}\n amountClassName={amountClass}\n />\n <span className={`items-center gap-2.5 ${secondaryClassName ?? \"flex\"}`}>\n {!stable && <span className={`${s.divider} w-px bg-border/60 shrink-0`} />}\n {stable ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <CoinChip symbol={currency} size={s.stableChip} />\n <span className=\"text-sm font-semibold text-muted-foreground\">{currency}</span>\n </span>\n ) : (\n <PriceUnit\n chip={<CoinChip symbol={currency} size={s.chip} />}\n amount={cryptoDisplay}\n label={s.showLabel ? (currency ?? undefined) : undefined}\n amountClassName={amountClass}\n />\n )}\n </span>\n {trailing && <span className=\"ml-0.5\">{trailing}</span>}\n </div>\n );\n}\n\nconst CHIP_TONES = {\n\n \"overlay-dark\": { dot: \"text-white/30\", text: \"text-white/65\" },\n\n card: { dot: \"text-muted-foreground/50\", text: \"text-muted-foreground\" },\n\n /** Same solid color as the primary USD figure — for cards that want a\n * single consistent shade instead of a muted secondary currency. */\n solid: { dot: \"text-foreground/40\", text: \"text-foreground\" },\n} as const;\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 {stripDollarSign(usdValue)}\n <span className={`font-semibold ${t.text}`}>USD</span>\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":[]}
|
|
@@ -58,26 +58,34 @@ function StatTile({
|
|
|
58
58
|
}
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
function StatPill({ value, label, className }) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
children:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
61
|
+
function StatPill({ value, label, className, active, onClick }) {
|
|
62
|
+
const classes = `inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm ${active ? "border-primary bg-primary/10 text-primary" : "border-border bg-card"} ${className ?? ""}`;
|
|
63
|
+
if (onClick) {
|
|
64
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", onClick, "aria-pressed": active, className: classes, children: [
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `font-bold tabular-nums ${active ? "" : "text-foreground"}`, children: value }),
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: active ? "" : "text-muted-foreground", children: label })
|
|
67
|
+
] });
|
|
68
|
+
}
|
|
69
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: classes, children: [
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-bold text-foreground tabular-nums", children: value }),
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: label })
|
|
72
|
+
] });
|
|
72
73
|
}
|
|
73
|
-
function StatPillRow({
|
|
74
|
-
|
|
74
|
+
function StatPillRow({
|
|
75
|
+
items,
|
|
76
|
+
className,
|
|
77
|
+
onSelect,
|
|
78
|
+
activeIndex
|
|
79
|
+
}) {
|
|
80
|
+
const shown = items.map((item, index) => ({ item, index })).filter(({ item }) => item.value !== void 0);
|
|
75
81
|
if (shown.length === 0) return null;
|
|
76
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `flex flex-wrap items-center gap-2 pt-0.5 ${className ?? ""}`, children: shown.map(({ label, value }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
82
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `flex flex-wrap items-center gap-2 pt-0.5 ${className ?? ""}`, children: shown.map(({ item: { label, value }, index }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
77
83
|
StatPill,
|
|
78
84
|
{
|
|
79
85
|
label,
|
|
80
|
-
value: value == null ? "\u2014" : typeof value === "number" ? value.toLocaleString() : value
|
|
86
|
+
value: value == null ? "\u2014" : typeof value === "number" ? value.toLocaleString() : value,
|
|
87
|
+
active: onSelect ? activeIndex === index : void 0,
|
|
88
|
+
onClick: onSelect ? () => onSelect(index) : void 0
|
|
81
89
|
},
|
|
82
90
|
label
|
|
83
91
|
)) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/stat-tile.tsx"],"sourcesContent":["\n\nexport interface StatTileProps {\n label: string;\n\n value?: string | number | null;\n\n sub?: string;\n\n accent?: string;\n\n big?: boolean;\n radius?: number;\n children?: React.ReactNode;\n className?: string;\n}\n\nexport function StatTile({\n label,\n value,\n sub,\n accent,\n big,\n radius = 16,\n children,\n className,\n}: StatTileProps) {\n return (\n <div\n className={`bg-muted border border-border flex flex-col gap-1 min-w-0 ${className ?? ''}`}\n style={{ borderRadius: radius, padding: '12px 14px' }}\n >\n <span className=\"text-[10.5px] font-semibold tracking-[0.06em] uppercase text-muted-foreground\">\n {label}\n </span>\n {value != null && (\n <span\n className=\"font-semibold leading-none tracking-tight tabular-nums\"\n style={{\n fontSize: big ? 22 : 16,\n color: accent,\n }}\n >\n {value}\n </span>\n )}\n {sub && (\n <span className=\"text-2xs text-muted-foreground\">{sub}</span>\n )}\n {children}\n </div>\n );\n}\n\nexport interface StatPillProps {\n value: string | number;\n label: string;\n className?: string;\n}\n\nexport function StatPill({ value, label, className }: StatPillProps) {\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/stat-tile.tsx"],"sourcesContent":["\n\nexport interface StatTileProps {\n label: string;\n\n value?: string | number | null;\n\n sub?: string;\n\n accent?: string;\n\n big?: boolean;\n radius?: number;\n children?: React.ReactNode;\n className?: string;\n}\n\nexport function StatTile({\n label,\n value,\n sub,\n accent,\n big,\n radius = 16,\n children,\n className,\n}: StatTileProps) {\n return (\n <div\n className={`bg-muted border border-border flex flex-col gap-1 min-w-0 ${className ?? ''}`}\n style={{ borderRadius: radius, padding: '12px 14px' }}\n >\n <span className=\"text-[10.5px] font-semibold tracking-[0.06em] uppercase text-muted-foreground\">\n {label}\n </span>\n {value != null && (\n <span\n className=\"font-semibold leading-none tracking-tight tabular-nums\"\n style={{\n fontSize: big ? 22 : 16,\n color: accent,\n }}\n >\n {value}\n </span>\n )}\n {sub && (\n <span className=\"text-2xs text-muted-foreground\">{sub}</span>\n )}\n {children}\n </div>\n );\n}\n\nexport interface StatPillProps {\n value: string | number;\n label: string;\n className?: string;\n active?: boolean;\n onClick?: () => void;\n}\n\nexport function StatPill({ value, label, className, active, onClick }: StatPillProps) {\n const classes = `inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm ${\n active ? \"border-primary bg-primary/10 text-primary\" : \"border-border bg-card\"\n } ${className ?? ''}`;\n\n if (onClick) {\n return (\n <button type=\"button\" onClick={onClick} aria-pressed={active} className={classes}>\n <span className={`font-bold tabular-nums ${active ? \"\" : \"text-foreground\"}`}>{value}</span>\n <span className={active ? \"\" : \"text-muted-foreground\"}>{label}</span>\n </button>\n );\n }\n\n return (\n <div className={classes}>\n <span className=\"font-bold text-foreground tabular-nums\">{value}</span>\n <span className=\"text-muted-foreground\">{label}</span>\n </div>\n );\n}\n\nexport interface StatPillRowItem {\n label: string;\n\n value?: number | string | null;\n}\n\nexport function StatPillRow({\n items,\n className,\n onSelect,\n activeIndex,\n}: {\n items: StatPillRowItem[];\n className?: string;\n onSelect?: (index: number) => void;\n activeIndex?: number;\n}) {\n const shown = items\n .map((item, index) => ({ item, index }))\n .filter(({ item }) => item.value !== undefined);\n if (shown.length === 0) return null;\n\n return (\n <div className={`flex flex-wrap items-center gap-2 pt-0.5 ${className ?? ''}`}>\n {shown.map(({ item: { label, value }, index }) => (\n <StatPill\n key={label}\n label={label}\n value={value == null ? \"—\" : typeof value === \"number\" ? value.toLocaleString() : value}\n active={onSelect ? activeIndex === index : undefined}\n onClick={onSelect ? () => onSelect(index) : undefined}\n />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BI;AAXG,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AACF,GAAkB;AAChB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,6DAA6D,aAAa,EAAE;AAAA,MACvF,OAAO,EAAE,cAAc,QAAQ,SAAS,YAAY;AAAA,MAEpD;AAAA,oDAAC,UAAK,WAAU,iFACb,iBACH;AAAA,QACC,SAAS,QACR;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,UAAU,MAAM,KAAK;AAAA,cACrB,OAAO;AAAA,YACT;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QAED,OACC,4CAAC,UAAK,WAAU,kCAAkC,eAAI;AAAA,QAEvD;AAAA;AAAA;AAAA,EACH;AAEJ;AAUO,SAAS,SAAS,EAAE,OAAO,OAAO,WAAW,QAAQ,QAAQ,GAAkB;AACpF,QAAM,UAAU,0EACd,SAAS,8CAA8C,uBACzD,IAAI,aAAa,EAAE;AAEnB,MAAI,SAAS;AACX,WACE,6CAAC,YAAO,MAAK,UAAS,SAAkB,gBAAc,QAAQ,WAAW,SACvE;AAAA,kDAAC,UAAK,WAAW,0BAA0B,SAAS,KAAK,iBAAiB,IAAK,iBAAM;AAAA,MACrF,4CAAC,UAAK,WAAW,SAAS,KAAK,yBAA0B,iBAAM;AAAA,OACjE;AAAA,EAEJ;AAEA,SACE,6CAAC,SAAI,WAAW,SACd;AAAA,gDAAC,UAAK,WAAU,0CAA0C,iBAAM;AAAA,IAChE,4CAAC,UAAK,WAAU,yBAAyB,iBAAM;AAAA,KACjD;AAEJ;AAQO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,MACX,IAAI,CAAC,MAAM,WAAW,EAAE,MAAM,MAAM,EAAE,EACtC,OAAO,CAAC,EAAE,KAAK,MAAM,KAAK,UAAU,MAAS;AAChD,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SACE,4CAAC,SAAI,WAAW,4CAA4C,aAAa,EAAE,IACxE,gBAAM,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,MAAM,GAAG,MAAM,MAC1C;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA,MACA,OAAO,SAAS,OAAO,WAAM,OAAO,UAAU,WAAW,MAAM,eAAe,IAAI;AAAA,MAClF,QAAQ,WAAW,gBAAgB,QAAQ;AAAA,MAC3C,SAAS,WAAW,MAAM,SAAS,KAAK,IAAI;AAAA;AAAA,IAJvC;AAAA,EAKP,CACD,GACH;AAEJ;","names":[]}
|
|
@@ -15,15 +15,19 @@ interface StatPillProps {
|
|
|
15
15
|
value: string | number;
|
|
16
16
|
label: string;
|
|
17
17
|
className?: string;
|
|
18
|
+
active?: boolean;
|
|
19
|
+
onClick?: () => void;
|
|
18
20
|
}
|
|
19
|
-
declare function StatPill({ value, label, className }: StatPillProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
declare function StatPill({ value, label, className, active, onClick }: StatPillProps): react_jsx_runtime.JSX.Element;
|
|
20
22
|
interface StatPillRowItem {
|
|
21
23
|
label: string;
|
|
22
24
|
value?: number | string | null;
|
|
23
25
|
}
|
|
24
|
-
declare function StatPillRow({ items, className }: {
|
|
26
|
+
declare function StatPillRow({ items, className, onSelect, activeIndex, }: {
|
|
25
27
|
items: StatPillRowItem[];
|
|
26
28
|
className?: string;
|
|
29
|
+
onSelect?: (index: number) => void;
|
|
30
|
+
activeIndex?: number;
|
|
27
31
|
}): react_jsx_runtime.JSX.Element | null;
|
|
28
32
|
|
|
29
33
|
export { StatPill, type StatPillProps, StatPillRow, type StatPillRowItem, StatTile, type StatTileProps };
|
|
@@ -15,15 +15,19 @@ interface StatPillProps {
|
|
|
15
15
|
value: string | number;
|
|
16
16
|
label: string;
|
|
17
17
|
className?: string;
|
|
18
|
+
active?: boolean;
|
|
19
|
+
onClick?: () => void;
|
|
18
20
|
}
|
|
19
|
-
declare function StatPill({ value, label, className }: StatPillProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
declare function StatPill({ value, label, className, active, onClick }: StatPillProps): react_jsx_runtime.JSX.Element;
|
|
20
22
|
interface StatPillRowItem {
|
|
21
23
|
label: string;
|
|
22
24
|
value?: number | string | null;
|
|
23
25
|
}
|
|
24
|
-
declare function StatPillRow({ items, className }: {
|
|
26
|
+
declare function StatPillRow({ items, className, onSelect, activeIndex, }: {
|
|
25
27
|
items: StatPillRowItem[];
|
|
26
28
|
className?: string;
|
|
29
|
+
onSelect?: (index: number) => void;
|
|
30
|
+
activeIndex?: number;
|
|
27
31
|
}): react_jsx_runtime.JSX.Element | null;
|
|
28
32
|
|
|
29
33
|
export { StatPill, type StatPillProps, StatPillRow, type StatPillRowItem, StatTile, type StatTileProps };
|