@medialane/ui 0.252.0 → 0.253.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/account/input-otp.d.cts +2 -2
- package/dist/components/account/input-otp.d.ts +2 -2
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/collection-card.cjs +11 -19
- package/dist/components/collection-card.cjs.map +1 -1
- package/dist/components/collection-card.js +11 -19
- package/dist/components/collection-card.js.map +1 -1
- package/dist/components/collections-page.cjs +190 -139
- package/dist/components/collections-page.cjs.map +1 -1
- package/dist/components/collections-page.js +181 -140
- package/dist/components/collections-page.js.map +1 -1
- package/dist/components/creator-page.cjs +1 -1
- package/dist/components/creator-page.cjs.map +1 -1
- package/dist/components/creator-page.js +1 -1
- package/dist/components/creator-page.js.map +1 -1
- package/dist/components/drop/create/drop-create.cjs +1 -1
- package/dist/components/drop/create/drop-create.cjs.map +1 -1
- package/dist/components/drop/create/drop-create.js +1 -1
- package/dist/components/drop/create/drop-create.js.map +1 -1
- package/dist/components/drop/create/launch-dialog.cjs +1 -1
- package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
- package/dist/components/drop/create/launch-dialog.js +1 -1
- package/dist/components/drop/create/launch-dialog.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/hero-slider.cjs +2 -1
- package/dist/components/hero-slider.cjs.map +1 -1
- package/dist/components/hero-slider.js +2 -1
- package/dist/components/hero-slider.js.map +1 -1
- package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
- package/dist/components/scroll-section.cjs +1 -1
- package/dist/components/scroll-section.cjs.map +1 -1
- package/dist/components/scroll-section.d.cts +1 -1
- package/dist/components/scroll-section.d.ts +1 -1
- package/dist/components/scroll-section.js +1 -1
- package/dist/components/scroll-section.js.map +1 -1
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- package/dist/utils/use-collections.cjs +1 -2
- package/dist/utils/use-collections.cjs.map +1 -1
- package/dist/utils/use-collections.js +1 -2
- package/dist/utils/use-collections.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect, useRef } from "react";
|
|
4
|
-
import
|
|
4
|
+
import useSWR from "swr";
|
|
5
|
+
import { Layers, BadgeCheck, Eye, SlidersHorizontal, Award, Package, ArrowDownUp, Search, X } from "lucide-react";
|
|
5
6
|
import { Button } from "./button.js";
|
|
6
7
|
import { Dialog, DialogContent, DialogTitle } from "./dialog.js";
|
|
8
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
|
|
7
9
|
import { HelpIcon } from "./help-icon.js";
|
|
10
|
+
import { Input } from "./input.js";
|
|
11
|
+
import { ResultThumbnail } from "./result-thumbnail.js";
|
|
12
|
+
import Link from "./link.js";
|
|
13
|
+
import { useRouter } from "./router.js";
|
|
8
14
|
import { PageContainer } from "./page-container.js";
|
|
15
|
+
import { ScrollSection } from "./scroll-section.js";
|
|
9
16
|
import { CollectionCard, CollectionCardSkeleton } from "./collection-card.js";
|
|
10
17
|
import { LoadMoreSentinel } from "./load-more-sentinel.js";
|
|
11
18
|
import { cn } from "../utils/cn.js";
|
|
12
19
|
import { useCollections } from "../utils/use-collections.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
20
|
+
import { useMedialaneClient } from "../utils/use-medialane-client.js";
|
|
21
|
+
import { SEARCH_MIN_LENGTH, useSearch } from "../utils/use-search.js";
|
|
22
|
+
import { collectionHref } from "@medialane/sdk";
|
|
23
|
+
const PAGE_SIZE = 24;
|
|
15
24
|
const SORT_OPTIONS = [
|
|
16
25
|
{ label: "Recent", value: "recent" },
|
|
17
26
|
{ label: "Most assets", value: "supply" },
|
|
@@ -24,12 +33,90 @@ const SERVICE_TABS = [
|
|
|
24
33
|
{ label: "POP Events", value: "pop-protocol" },
|
|
25
34
|
{ label: "Drops", value: "drop-collection" }
|
|
26
35
|
];
|
|
36
|
+
function useStandardCounts() {
|
|
37
|
+
const client = useMedialaneClient();
|
|
38
|
+
const { data } = useSWR(
|
|
39
|
+
"collection-standard-counts",
|
|
40
|
+
async () => {
|
|
41
|
+
const [single, multi] = await Promise.all(
|
|
42
|
+
["ERC721", "ERC1155"].map(
|
|
43
|
+
(standard) => client.api.collections.list({ standard, hideEmpty: true, limit: 1 })
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
return { single: single.meta?.total, multi: multi.meta?.total };
|
|
47
|
+
},
|
|
48
|
+
{ revalidateOnFocus: false, dedupingInterval: 6e4 }
|
|
49
|
+
);
|
|
50
|
+
return data ?? null;
|
|
51
|
+
}
|
|
52
|
+
function CollectionSearch() {
|
|
53
|
+
const router = useRouter();
|
|
54
|
+
const [value, setValue] = useState("");
|
|
55
|
+
const [query, setQuery] = useState("");
|
|
56
|
+
const [open, setOpen] = useState(false);
|
|
57
|
+
const { results } = useSearch(query, { limit: 6 });
|
|
58
|
+
const matches = results?.collections ?? [];
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const timer = setTimeout(() => setQuery(value), 300);
|
|
61
|
+
return () => clearTimeout(timer);
|
|
62
|
+
}, [value]);
|
|
63
|
+
const clear = () => {
|
|
64
|
+
setValue("");
|
|
65
|
+
setQuery("");
|
|
66
|
+
setOpen(false);
|
|
67
|
+
};
|
|
68
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative w-full sm:max-w-sm sm:flex-1", children: [
|
|
69
|
+
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
Input,
|
|
72
|
+
{
|
|
73
|
+
className: "h-9 pl-9 pr-9 text-sm",
|
|
74
|
+
placeholder: "Search collections",
|
|
75
|
+
"aria-label": "Search collections",
|
|
76
|
+
value,
|
|
77
|
+
onChange: (e) => {
|
|
78
|
+
setValue(e.target.value);
|
|
79
|
+
setOpen(true);
|
|
80
|
+
},
|
|
81
|
+
onFocus: () => setOpen(true),
|
|
82
|
+
onBlur: () => setTimeout(() => setOpen(false), 200),
|
|
83
|
+
onKeyDown: (e) => {
|
|
84
|
+
if (e.key === "Enter" && value.trim().length >= SEARCH_MIN_LENGTH) {
|
|
85
|
+
router.push(`/search?q=${encodeURIComponent(value.trim())}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
value && /* @__PURE__ */ jsx(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
"aria-label": "Clear search",
|
|
94
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground",
|
|
95
|
+
onClick: clear,
|
|
96
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
open && matches.length > 0 && /* @__PURE__ */ jsx("div", { className: "absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg", children: matches.map((col) => {
|
|
100
|
+
const label = col.name ?? "Untitled";
|
|
101
|
+
return /* @__PURE__ */ jsxs(
|
|
102
|
+
Link,
|
|
103
|
+
{
|
|
104
|
+
href: collectionHref("STARKNET", col.contractAddress),
|
|
105
|
+
className: "flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50",
|
|
106
|
+
children: [
|
|
107
|
+
/* @__PURE__ */ jsx(ResultThumbnail, { src: col.image, label }),
|
|
108
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium", children: label })
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
col.contractAddress
|
|
112
|
+
);
|
|
113
|
+
}) })
|
|
114
|
+
] });
|
|
115
|
+
}
|
|
27
116
|
function CollectionsPage() {
|
|
28
|
-
const
|
|
117
|
+
const counts = useStandardCounts();
|
|
29
118
|
const [sort, setSort] = useState("recent");
|
|
30
|
-
const [featured, setFeatured] = useState(false);
|
|
31
119
|
const [hideEmpty, setHideEmpty] = useState(true);
|
|
32
|
-
const [exclusive, setExclusive] = useState(false);
|
|
33
120
|
const [service, setService] = useState(void 0);
|
|
34
121
|
const [filtersOpen, setFiltersOpen] = useState(false);
|
|
35
122
|
const [page, setPage] = useState(1);
|
|
@@ -37,21 +124,30 @@ function CollectionsPage() {
|
|
|
37
124
|
const { collections, meta, isLoading } = useCollections(
|
|
38
125
|
page,
|
|
39
126
|
PAGE_SIZE,
|
|
40
|
-
|
|
127
|
+
void 0,
|
|
41
128
|
sort,
|
|
42
129
|
service === "pop-protocol" || service === "drop-collection" ? false : hideEmpty,
|
|
43
130
|
service,
|
|
44
131
|
"ERC721,ERC1155"
|
|
45
132
|
);
|
|
46
|
-
const
|
|
133
|
+
const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(
|
|
134
|
+
1,
|
|
135
|
+
8,
|
|
136
|
+
true,
|
|
137
|
+
"recent",
|
|
138
|
+
true,
|
|
139
|
+
void 0,
|
|
140
|
+
"ERC721,ERC1155"
|
|
141
|
+
);
|
|
142
|
+
const prevFilters = useRef({ sort, hideEmpty, service });
|
|
47
143
|
useEffect(() => {
|
|
48
144
|
const f = prevFilters.current;
|
|
49
|
-
if (f.sort !== sort || f.
|
|
50
|
-
prevFilters.current = { sort,
|
|
145
|
+
if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {
|
|
146
|
+
prevFilters.current = { sort, hideEmpty, service };
|
|
51
147
|
setPage(1);
|
|
52
148
|
setAllCollections([]);
|
|
53
149
|
}
|
|
54
|
-
}, [sort,
|
|
150
|
+
}, [sort, hideEmpty, service]);
|
|
55
151
|
useEffect(() => {
|
|
56
152
|
if (isLoading || collections.length === 0) return;
|
|
57
153
|
setAllCollections((prev) => {
|
|
@@ -62,13 +158,9 @@ function CollectionsPage() {
|
|
|
62
158
|
}, [collections, isLoading, page]);
|
|
63
159
|
const hasMore = meta?.total != null ? allCollections.length < meta.total : false;
|
|
64
160
|
const isInitialLoading = isLoading && allCollections.length === 0;
|
|
65
|
-
const activeFilters = [
|
|
66
|
-
const displayCollections = exclusive ? allCollections.filter((c) => !!c.profile?.hasGatedContent) : allCollections;
|
|
161
|
+
const activeFilters = [!hideEmpty].filter(Boolean).length;
|
|
67
162
|
const resetAll = () => {
|
|
68
|
-
setSort("recent");
|
|
69
|
-
setFeatured(false);
|
|
70
163
|
setHideEmpty(true);
|
|
71
|
-
setExclusive(false);
|
|
72
164
|
};
|
|
73
165
|
const handleServiceChange = (val) => {
|
|
74
166
|
setService(val);
|
|
@@ -77,58 +169,63 @@ function CollectionsPage() {
|
|
|
77
169
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2 pt-8", children: [
|
|
78
170
|
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold", children: "Onchain Collections" }),
|
|
79
171
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 mt-1", children: [
|
|
80
|
-
|
|
81
|
-
/* @__PURE__ */ jsx("span", { className: "font-bold tabular-nums", children:
|
|
82
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "
|
|
83
|
-
] }),
|
|
84
|
-
stats?.tokens != null && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm", children: [
|
|
85
|
-
/* @__PURE__ */ jsx("span", { className: "font-bold tabular-nums", children: stats.tokens.toLocaleString() }),
|
|
86
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Assets" })
|
|
172
|
+
counts?.single != null && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm", children: [
|
|
173
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold tabular-nums", children: counts.single.toLocaleString() }),
|
|
174
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Single NFTs" })
|
|
87
175
|
] }),
|
|
88
|
-
|
|
89
|
-
/* @__PURE__ */ jsx("span", { className: "font-bold tabular-nums", children:
|
|
90
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "
|
|
176
|
+
counts?.multi != null && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm", children: [
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "font-bold tabular-nums", children: counts.multi.toLocaleString() }),
|
|
178
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Multi editions" })
|
|
91
179
|
] })
|
|
92
180
|
] })
|
|
93
181
|
] }),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
182
|
+
(featuredLoading || featuredCollections.length > 0) && /* @__PURE__ */ jsx(
|
|
183
|
+
ScrollSection,
|
|
184
|
+
{
|
|
185
|
+
icon: /* @__PURE__ */ jsx(BadgeCheck, { className: "h-3.5 w-3.5 text-white" }),
|
|
186
|
+
iconBg: "bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20",
|
|
187
|
+
title: "Featured",
|
|
188
|
+
children: featuredLoading ? Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "w-56 shrink-0 snap-start sm:w-64", children: /* @__PURE__ */ jsx(CollectionCardSkeleton, {}) }, i)) : featuredCollections.map((col) => /* @__PURE__ */ jsx("div", { className: "w-56 shrink-0 snap-start sm:w-64", children: /* @__PURE__ */ jsx(CollectionCard, { collection: col }) }, col.contractAddress))
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
192
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
193
|
+
/* @__PURE__ */ jsx(CollectionSearch, {}),
|
|
194
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 sm:ml-auto", children: [
|
|
195
|
+
/* @__PURE__ */ jsxs(Select, { value: sort, onValueChange: (v) => setSort(v), children: [
|
|
196
|
+
/* @__PURE__ */ jsxs(SelectTrigger, { className: "h-9 w-auto gap-1.5 text-xs", "aria-label": "Sort collections", children: [
|
|
197
|
+
/* @__PURE__ */ jsx(ArrowDownUp, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
198
|
+
/* @__PURE__ */ jsx(SelectValue, {})
|
|
199
|
+
] }),
|
|
200
|
+
/* @__PURE__ */ jsx(SelectContent, { children: SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt.value, className: "text-xs", children: opt.label }, opt.value)) })
|
|
201
|
+
] }),
|
|
202
|
+
/* @__PURE__ */ jsxs(
|
|
203
|
+
"button",
|
|
204
|
+
{
|
|
205
|
+
onClick: () => setFiltersOpen(true),
|
|
206
|
+
className: cn(
|
|
207
|
+
"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors",
|
|
208
|
+
activeFilters > 0 || service !== void 0 ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50 hover:text-foreground"
|
|
209
|
+
),
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
212
|
+
"Filters",
|
|
213
|
+
(activeFilters > 0 || service !== void 0) && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground", children: activeFilters + (service !== void 0 ? 1 : 0) })
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
] })
|
|
127
218
|
] }),
|
|
128
|
-
|
|
129
|
-
/* @__PURE__ */
|
|
130
|
-
|
|
131
|
-
|
|
219
|
+
(service !== void 0 || !hideEmpty) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
220
|
+
service !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary", children: [
|
|
221
|
+
service === "drop-collection" ? /* @__PURE__ */ jsx(Package, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Award, { className: "h-3 w-3" }),
|
|
222
|
+
SERVICE_TABS.find((t) => t.value === service)?.label,
|
|
223
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setService(void 0), className: "ml-0.5 hover:text-primary/60", "aria-label": "Remove source filter", children: "\xD7" })
|
|
224
|
+
] }),
|
|
225
|
+
!hideEmpty && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary", children: [
|
|
226
|
+
"Show empty",
|
|
227
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setHideEmpty(true), className: "ml-0.5 hover:text-primary/60", "aria-label": "Remove show empty filter", children: "\xD7" })
|
|
228
|
+
] })
|
|
132
229
|
] })
|
|
133
230
|
] }),
|
|
134
231
|
/* @__PURE__ */ jsx(Dialog, { open: filtersOpen, onOpenChange: setFiltersOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]", children: [
|
|
@@ -162,92 +259,36 @@ function CollectionsPage() {
|
|
|
162
259
|
label
|
|
163
260
|
)) })
|
|
164
261
|
] }),
|
|
165
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
166
|
-
/* @__PURE__ */ jsx("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Sort" }),
|
|
167
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsx(
|
|
168
|
-
"button",
|
|
169
|
-
{
|
|
170
|
-
onClick: () => setSort(opt.value),
|
|
171
|
-
className: cn(
|
|
172
|
-
"text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap",
|
|
173
|
-
sort === opt.value ? "border-primary bg-primary/10 text-primary font-medium" : "border-border text-muted-foreground hover:border-primary/50"
|
|
174
|
-
),
|
|
175
|
-
children: opt.label
|
|
176
|
-
},
|
|
177
|
-
opt.value
|
|
178
|
-
)) })
|
|
179
|
-
] }),
|
|
180
262
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
181
263
|
/* @__PURE__ */ jsx("p", { className: "text-2xs font-semibold text-muted-foreground", children: "Show" }),
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */ jsxs(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
] }),
|
|
200
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
201
|
-
/* @__PURE__ */ jsxs(
|
|
202
|
-
"button",
|
|
203
|
-
{
|
|
204
|
-
onClick: () => setHideEmpty((v) => !v),
|
|
205
|
-
className: cn(
|
|
206
|
-
"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left",
|
|
207
|
-
!hideEmpty ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50"
|
|
208
|
-
),
|
|
209
|
-
children: [
|
|
210
|
-
/* @__PURE__ */ jsx(Eye, { className: "h-4 w-4 shrink-0" }),
|
|
211
|
-
"Show empty collections"
|
|
212
|
-
]
|
|
213
|
-
}
|
|
214
|
-
),
|
|
215
|
-
/* @__PURE__ */ jsx(HelpIcon, { content: "Include collections with no minted assets yet \u2014 hidden by default to keep the feed clean", side: "left" })
|
|
216
|
-
] }),
|
|
217
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
218
|
-
/* @__PURE__ */ jsxs(
|
|
219
|
-
"button",
|
|
220
|
-
{
|
|
221
|
-
onClick: () => setExclusive((v) => !v),
|
|
222
|
-
className: cn(
|
|
223
|
-
"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left",
|
|
224
|
-
exclusive ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50"
|
|
225
|
-
),
|
|
226
|
-
children: [
|
|
227
|
-
/* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4 shrink-0" }),
|
|
228
|
-
"Exclusive content only"
|
|
229
|
-
]
|
|
230
|
-
}
|
|
231
|
-
),
|
|
232
|
-
/* @__PURE__ */ jsx(HelpIcon, { content: "Show only collections with holder-exclusive content", side: "left" })
|
|
233
|
-
] })
|
|
234
|
-
] })
|
|
264
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
265
|
+
/* @__PURE__ */ jsxs(
|
|
266
|
+
"button",
|
|
267
|
+
{
|
|
268
|
+
onClick: () => setHideEmpty((v) => !v),
|
|
269
|
+
className: cn(
|
|
270
|
+
"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left",
|
|
271
|
+
!hideEmpty ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:border-primary/50"
|
|
272
|
+
),
|
|
273
|
+
children: [
|
|
274
|
+
/* @__PURE__ */ jsx(Eye, { className: "h-4 w-4 shrink-0" }),
|
|
275
|
+
"Show empty collections"
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
/* @__PURE__ */ jsx(HelpIcon, { content: "Include collections with no minted assets yet \u2014 hidden by default to keep the feed clean", side: "left" })
|
|
280
|
+
] }) })
|
|
235
281
|
] })
|
|
236
282
|
] }),
|
|
237
|
-
/* @__PURE__ */ jsx("div", { className: "px-5 py-3 border-t border-border/60", children: /* @__PURE__ */ jsx(Button, { className: "w-full", onClick: () => setFiltersOpen(false), children: "
|
|
283
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 py-3 border-t border-border/60", children: /* @__PURE__ */ jsx(Button, { className: "w-full", onClick: () => setFiltersOpen(false), children: "Show results" }) })
|
|
238
284
|
] }) }),
|
|
239
|
-
isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-
|
|
285
|
+
isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-5", children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ jsx(CollectionCardSkeleton, {}, i)) }) : allCollections.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-24 gap-4 text-center", children: [
|
|
240
286
|
/* @__PURE__ */ jsx(Layers, { className: "h-12 w-12 text-muted-foreground/30" }),
|
|
241
287
|
/* @__PURE__ */ jsx("p", { className: "text-2xl font-bold", children: "No collections found" }),
|
|
242
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground max-w-sm", children:
|
|
288
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground max-w-sm", children: hideEmpty ? "No collections with assets yet." : "Deploy the first collection on Medialane." }),
|
|
243
289
|
activeFilters > 0 && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: resetAll, children: "Clear filters" })
|
|
244
290
|
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
245
|
-
|
|
246
|
-
/* @__PURE__ */ jsx(Sparkles, { className: "h-10 w-10 text-muted-foreground/30" }),
|
|
247
|
-
/* @__PURE__ */ jsx("p", { className: "text-base font-semibold text-muted-foreground", children: "No exclusive collections in this batch" }),
|
|
248
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground/70 max-w-xs", children: "Load more collections below, then the filter will catch them." })
|
|
249
|
-
] }),
|
|
250
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5", children: displayCollections.map((col) => /* @__PURE__ */ jsx(CollectionCard, { collection: col }, col.contractAddress)) }),
|
|
291
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-5", children: allCollections.map((col) => /* @__PURE__ */ jsx(CollectionCard, { collection: col }, col.contractAddress)) }),
|
|
251
292
|
/* @__PURE__ */ jsx(
|
|
252
293
|
LoadMoreSentinel,
|
|
253
294
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport { Layers, BadgeCheck, Eye, SlidersHorizontal, Award, Sparkles, Package } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { usePlatformStats } from \"../utils/use-platform-stats.js\";\nimport type { ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 18;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nexport function CollectionsPage() {\n const { stats } = usePlatformStats();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [featured, setFeatured] = useState(false);\n const [hideEmpty, setHideEmpty] = useState(true);\n const [exclusive, setExclusive] = useState(false);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n featured ? true : undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, featured, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.featured !== featured || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, featured, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, featured, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [sort !== \"recent\", featured, !hideEmpty, exclusive].filter(Boolean).length;\n\n const displayCollections = exclusive\n ? allCollections.filter((c) => !!c.profile?.hasGatedContent)\n : allCollections;\n\n const resetAll = () => {\n setSort(\"recent\");\n setFeatured(false);\n setHideEmpty(true);\n setExclusive(false);\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {meta?.total != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{(meta.total ?? 0).toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Collections</span>\n </div>\n )}\n {stats?.tokens != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{stats.tokens.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Assets</span>\n </div>\n )}\n {stats?.sales != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{stats.sales.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Sales</span>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 pb-3 border-b border-border/60 flex-wrap\">\n <button\n onClick={() => setFiltersOpen(true)}\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\">×</button>\n </span>\n )}\n {sort !== \"recent\" && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {SORT_OPTIONS.find((o) => o.value === sort)?.label}\n <button onClick={() => setSort(\"recent\")} className=\"ml-0.5 hover:text-primary/60\">×</button>\n </span>\n )}\n {featured && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n <BadgeCheck className=\"h-3 w-3\" />\n Featured\n <button onClick={() => setFeatured(false)} className=\"ml-0.5 hover:text-primary/60\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\">×</button>\n </span>\n )}\n {exclusive && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n <Sparkles className=\"h-3 w-3\" />\n Exclusive\n <button onClick={() => setExclusive(false)} className=\"ml-0.5 hover:text-primary/60\">×</button>\n </span>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Sort</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n onClick={() => setSort(opt.value)}\n className={cn(\n \"text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n sort === opt.value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setFeatured((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n featured\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <BadgeCheck className=\"h-4 w-4 shrink-0\" />\n Featured only\n </button>\n <HelpIcon content=\"Show only collections featured by Medialane\" side=\"left\" />\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setExclusive((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n exclusive\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Sparkles className=\"h-4 w-4 shrink-0\" />\n Exclusive content only\n </button>\n <HelpIcon content=\"Show only collections with holder-exclusive content\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Apply filters\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5\">\n {Array.from({ length: 9 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {featured\n ? \"No featured collections match the current filters.\"\n : hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {exclusive && displayCollections.length === 0 && (\n <div className=\"flex flex-col items-center justify-center py-16 gap-3 text-center\">\n <Sparkles className=\"h-10 w-10 text-muted-foreground/30\" />\n <p className=\"text-base font-semibold text-muted-foreground\">No exclusive collections in this batch</p>\n <p className=\"text-sm text-muted-foreground/70 max-w-xs\">Load more collections below, then the filter will catch them.</p>\n </div>\n )}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-5\">\n {displayCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/collections-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport { Layers, BadgeCheck, Eye, SlidersHorizontal, Award, Package, ArrowDownUp, Search, X } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"./select.js\";\nimport { HelpIcon } from \"./help-icon.js\";\nimport { Input } from \"./input.js\";\nimport { ResultThumbnail } from \"./result-thumbnail.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { ScrollSection } from \"./scroll-section.js\";\nimport { CollectionCard, CollectionCardSkeleton } from \"./collection-card.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { useCollections, type CollectionSort } from \"../utils/use-collections.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { SEARCH_MIN_LENGTH, useSearch } from \"../utils/use-search.js\";\nimport { collectionHref, type ApiCollection } from \"@medialane/sdk\";\n\nconst PAGE_SIZE = 24;\n\nconst SORT_OPTIONS: { label: string; value: CollectionSort }[] = [\n { label: \"Recent\", value: \"recent\" },\n { label: \"Most assets\", value: \"supply\" },\n { label: \"Top volume\", value: \"volume\" },\n { label: \"Floor ↑\", value: \"floor\" },\n { label: \"A → Z\", value: \"name\" },\n];\n\nconst SERVICE_TABS = [\n { label: \"All\", value: undefined },\n { label: \"POP Events\", value: \"pop-protocol\" },\n { label: \"Drops\", value: \"drop-collection\" },\n] as const;\n\nfunction useStandardCounts() {\n const client = useMedialaneClient();\n const { data } = useSWR(\n \"collection-standard-counts\",\n async () => {\n const [single, multi] = await Promise.all(\n [\"ERC721\", \"ERC1155\"].map((standard) =>\n client.api.collections.list({ standard, hideEmpty: true, limit: 1 })\n )\n );\n return { single: single.meta?.total, multi: multi.meta?.total };\n },\n { revalidateOnFocus: false, dedupingInterval: 60_000 }\n );\n return data ?? null;\n}\n\nfunction CollectionSearch() {\n const router = useRouter();\n const [value, setValue] = useState(\"\");\n const [query, setQuery] = useState(\"\");\n const [open, setOpen] = useState(false);\n const { results } = useSearch(query, { limit: 6 });\n const matches = results?.collections ?? [];\n\n useEffect(() => {\n const timer = setTimeout(() => setQuery(value), 300);\n return () => clearTimeout(timer);\n }, [value]);\n\n const clear = () => {\n setValue(\"\");\n setQuery(\"\");\n setOpen(false);\n };\n\n return (\n <div className=\"relative w-full sm:max-w-sm sm:flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n className=\"h-9 pl-9 pr-9 text-sm\"\n placeholder=\"Search collections\"\n aria-label=\"Search collections\"\n value={value}\n onChange={(e) => { setValue(e.target.value); setOpen(true); }}\n onFocus={() => setOpen(true)}\n onBlur={() => setTimeout(() => setOpen(false), 200)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && value.trim().length >= SEARCH_MIN_LENGTH) {\n router.push(`/search?q=${encodeURIComponent(value.trim())}`);\n }\n }}\n />\n {value && (\n <button\n aria-label=\"Clear search\"\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground\"\n onClick={clear}\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n {open && matches.length > 0 && (\n <div className=\"absolute left-0 right-0 top-full z-50 mt-1 overflow-hidden rounded-xl border border-border bg-popover shadow-lg\">\n {matches.map((col) => {\n const label = col.name ?? \"Untitled\";\n return (\n <Link\n key={col.contractAddress}\n href={collectionHref(\"STARKNET\", col.contractAddress)}\n className=\"flex items-center gap-3 px-3 py-2.5 transition-colors hover:bg-muted/50\"\n >\n <ResultThumbnail src={col.image} label={label} />\n <span className=\"truncate text-sm font-medium\">{label}</span>\n </Link>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport function CollectionsPage() {\n const counts = useStandardCounts();\n const [sort, setSort] = useState<CollectionSort>(\"recent\");\n const [hideEmpty, setHideEmpty] = useState(true);\n const [service, setService] = useState<string | undefined>(undefined);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [page, setPage] = useState(1);\n const [allCollections, setAllCollections] = useState<ApiCollection[]>([]);\n\n const { collections, meta, isLoading } = useCollections(\n page,\n PAGE_SIZE,\n undefined,\n sort,\n service === \"pop-protocol\" || service === \"drop-collection\" ? false : hideEmpty,\n service,\n \"ERC721,ERC1155\"\n );\n\n const { collections: featuredCollections, isLoading: featuredLoading } = useCollections(\n 1,\n 8,\n true,\n \"recent\",\n true,\n undefined,\n \"ERC721,ERC1155\"\n );\n\n const prevFilters = useRef({ sort, hideEmpty, service });\n useEffect(() => {\n const f = prevFilters.current;\n if (f.sort !== sort || f.hideEmpty !== hideEmpty || f.service !== service) {\n prevFilters.current = { sort, hideEmpty, service };\n setPage(1);\n setAllCollections([]);\n }\n }, [sort, hideEmpty, service]);\n\n useEffect(() => {\n if (isLoading || collections.length === 0) return;\n setAllCollections((prev) => {\n const ids = new Set(prev.map((c) => c.contractAddress));\n const next = collections.filter((c) => !ids.has(c.contractAddress));\n return page === 1 ? collections : [...prev, ...next];\n });\n }, [collections, isLoading, page]);\n\n const hasMore = meta?.total != null ? allCollections.length < meta.total : false;\n const isInitialLoading = isLoading && allCollections.length === 0;\n\n const activeFilters = [!hideEmpty].filter(Boolean).length;\n\n const resetAll = () => {\n setHideEmpty(true);\n };\n\n const handleServiceChange = (val: string | undefined) => {\n setService(val);\n };\n\n return (\n <PageContainer className=\"box-border max-w-full pt-14 pb-8 space-y-8\">\n\n <div className=\"space-y-2 pt-8\">\n\n <h1 className=\"text-3xl font-bold\">Onchain Collections</h1>\n <div className=\"flex flex-wrap items-center gap-2 mt-1\">\n {counts?.single != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.single.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Single NFTs</span>\n </div>\n )}\n {counts?.multi != null && (\n <div className=\"flex items-center gap-1.5 rounded-full border border-border bg-card px-3.5 py-1.5 text-sm\">\n <span className=\"font-bold tabular-nums\">{counts.multi.toLocaleString()}</span>\n <span className=\"text-muted-foreground\">Multi editions</span>\n </div>\n )}\n </div>\n </div>\n\n {(featuredLoading || featuredCollections.length > 0) && (\n <ScrollSection\n icon={<BadgeCheck className=\"h-3.5 w-3.5 text-white\" />}\n iconBg=\"bg-gradient-to-br from-brand-blue to-indigo-600 shadow-md shadow-brand-blue/20\"\n title=\"Featured\"\n >\n {featuredLoading\n ? Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"w-56 shrink-0 snap-start sm:w-64\"><CollectionCardSkeleton /></div>\n ))\n : featuredCollections.map((col) => (\n <div key={col.contractAddress} className=\"w-56 shrink-0 snap-start sm:w-64\">\n <CollectionCard collection={col} />\n </div>\n ))}\n </ScrollSection>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <CollectionSearch />\n <div className=\"flex items-center gap-2 sm:ml-auto\">\n <Select value={sort} onValueChange={(v) => setSort(v as CollectionSort)}>\n <SelectTrigger className=\"h-9 w-auto gap-1.5 text-xs\" aria-label=\"Sort collections\">\n <ArrowDownUp className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {SORT_OPTIONS.map((opt) => (\n <SelectItem key={opt.value} value={opt.value} className=\"text-xs\">{opt.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n <button\n onClick={() => setFiltersOpen(true)}\n className={cn(\n \"relative flex items-center gap-1.5 h-9 px-3 rounded-lg border text-xs font-medium transition-colors\",\n activeFilters > 0 || service !== undefined\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50 hover:text-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {(activeFilters > 0 || service !== undefined) && (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-primary text-2xs font-bold text-primary-foreground\">\n {activeFilters + (service !== undefined ? 1 : 0)}\n </span>\n )}\n </button>\n </div>\n </div>\n {(service !== undefined || !hideEmpty) && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {service !== undefined && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n {service === \"drop-collection\" ? <Package className=\"h-3 w-3\" /> : <Award className=\"h-3 w-3\" />}\n {SERVICE_TABS.find((t) => t.value === service)?.label}\n <button onClick={() => setService(undefined)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove source filter\">×</button>\n </span>\n )}\n {!hideEmpty && (\n <span className=\"flex items-center gap-1 text-xs px-2.5 py-1 rounded-full border border-primary/40 bg-primary/10 text-primary\">\n Show empty\n <button onClick={() => setHideEmpty(true)} className=\"ml-0.5 hover:text-primary/60\" aria-label=\"Remove show empty filter\">×</button>\n </span>\n )}\n </div>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {(activeFilters > 0 || service !== undefined) && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={() => { resetAll(); setService(undefined); }}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Source</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {SERVICE_TABS.map(({ label, value }) => (\n <button\n key={label}\n onClick={() => handleServiceChange(value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n service === value\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {value === \"pop-protocol\" && <Award className=\"h-3 w-3\" />}\n {value === \"drop-collection\" && <Package className=\"h-3 w-3\" />}\n {label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Show</p>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setHideEmpty((v) => !v)}\n className={cn(\n \"flex flex-1 items-center gap-2 text-sm px-3 py-2 rounded-lg border transition-colors text-left\",\n !hideEmpty\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <Eye className=\"h-4 w-4 shrink-0\" />\n Show empty collections\n </button>\n <HelpIcon content=\"Include collections with no minted assets yet — hidden by default to keep the feed clean\" side=\"left\" />\n </div>\n </div>\n </div>\n\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Show results\n </Button>\n </div>\n\n </DialogContent>\n </Dialog>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-5\">\n {Array.from({ length: 8 }).map((_, i) => <CollectionCardSkeleton key={i} />)}\n </div>\n ) : allCollections.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-24 gap-4 text-center\">\n <Layers className=\"h-12 w-12 text-muted-foreground/30\" />\n <p className=\"text-2xl font-bold\">No collections found</p>\n <p className=\"text-muted-foreground max-w-sm\">\n {hideEmpty\n ? \"No collections with assets yet.\"\n : \"Deploy the first collection on Medialane.\"}\n </p>\n {activeFilters > 0 && (\n <Button variant=\"outline\" size=\"sm\" onClick={resetAll}>\n Clear filters\n </Button>\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-5\">\n {allCollections.map((col) => (\n <CollectionCard key={col.contractAddress} collection={col} />\n ))}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoading}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -175,7 +175,7 @@ function CreatorPage({ address: addressProp, username, useAssetActions, useMarke
|
|
|
175
175
|
`${t.contractAddress}-${t.tokenId}`
|
|
176
176
|
);
|
|
177
177
|
}) })),
|
|
178
|
-
activeTab === "collections" && (collectionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-
|
|
178
|
+
activeTab === "collections" && (collectionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-2 gap-4 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collection_card.CollectionCardSkeleton, {}, i)) }) : collections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tab_empty_state.TabEmptyState, { icon: import_lucide_react.LayoutGrid, heading: "No collections yet", body: "Collections this creator makes appear here." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-2 gap-4 lg:grid-cols-3", children: collections.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collection_card.CollectionCard, { collection: c }, c.contractAddress)) })),
|
|
179
179
|
activeTab === "listings" && (ordersLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: GRID, children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_listing_card.ListingCardSkeleton, {}, i)) }) : listings.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tab_empty_state.TabEmptyState, { icon: import_lucide_react.ShoppingBag, heading: "No active listings", body: "Works this creator lists for sale appear here." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: GRID, children: listings.map((o) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_listing_card.ListingCard, { order: o, onBuy: isOwner ? void 0 : market.buy, usdValue: (0, import_order_usd.orderUsd)(o.price, prices), overflowMenu: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_listing_card_menu.ListingCardMenu, { order: o }) }, o.orderHash)) })),
|
|
180
180
|
activeTab === "analytics" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-2xl", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-64 w-full animate-pulse rounded-xl bg-muted/40" }), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CreatorAnalytics, { activities, isLoading: activitiesLoading }) }) }),
|
|
181
181
|
activeTab === "activity" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-2xl", children: activitiesLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-5", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-10 w-full rounded-xl" }, i)) }) : activities.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tab_empty_state.TabEmptyState, { icon: import_lucide_react.Activity, heading: "No activity yet", body: "This creator's activity appears here as it happens." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: activities.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_activity_timeline_row.ActivityTimelineRow, { event: a, isLast: i === activities.length - 1 }, i)) }) })
|