@medialane/ui 0.162.0 → 0.164.1
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/activities-feed.cjs +211 -0
- package/dist/components/activities-feed.cjs.map +1 -0
- package/dist/components/activities-feed.d.cts +9 -0
- package/dist/components/activities-feed.d.ts +9 -0
- package/dist/components/activities-feed.js +177 -0
- package/dist/components/activities-feed.js.map +1 -0
- package/dist/components/button.d.cts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/fast-mint/dropzone.d.cts +1 -0
- package/dist/components/fast-mint/dropzone.d.ts +1 -0
- package/dist/components/fast-mint/fast-mint.cjs +3 -1
- package/dist/components/fast-mint/fast-mint.cjs.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/fast-mint/fast-mint.js +3 -1
- package/dist/components/fast-mint/fast-mint.js.map +1 -1
- package/dist/components/fast-mint/success-view.cjs +2 -0
- package/dist/components/fast-mint/success-view.cjs.map +1 -1
- package/dist/components/fast-mint/success-view.d.cts +3 -1
- package/dist/components/fast-mint/success-view.d.ts +3 -1
- package/dist/components/fast-mint/success-view.js +2 -0
- package/dist/components/fast-mint/success-view.js.map +1 -1
- package/dist/components/fast-mint/types.cjs.map +1 -1
- package/dist/components/fast-mint/types.d.cts +2 -0
- package/dist/components/fast-mint/types.d.ts +2 -0
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- 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/dist/utils/notification-readiness.cjs +32 -0
- package/dist/utils/notification-readiness.cjs.map +1 -0
- package/dist/utils/notification-readiness.d.cts +9 -0
- package/dist/utils/notification-readiness.d.ts +9 -0
- package/dist/utils/notification-readiness.js +8 -0
- package/dist/utils/notification-readiness.js.map +1 -0
- package/dist/utils/use-notifications.cjs +15 -4
- package/dist/utils/use-notifications.cjs.map +1 -1
- package/dist/utils/use-notifications.d.cts +1 -0
- package/dist/utils/use-notifications.d.ts +1 -0
- package/dist/utils/use-notifications.js +16 -5
- package/dist/utils/use-notifications.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var activities_feed_exports = {};
|
|
31
|
+
__export(activities_feed_exports, {
|
|
32
|
+
ActivitiesFeed: () => ActivitiesFeed
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(activities_feed_exports);
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var import_react = require("react");
|
|
37
|
+
var import_swr = __toESM(require("swr"), 1);
|
|
38
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
39
|
+
var import_use_activities = require("../utils/use-activities.js");
|
|
40
|
+
var import_use_rewards = require("../utils/use-rewards.js");
|
|
41
|
+
var import_skeleton = require("./skeleton.js");
|
|
42
|
+
var import_load_more_sentinel = require("./load-more-sentinel.js");
|
|
43
|
+
var import_lucide_react = require("lucide-react");
|
|
44
|
+
var import_activity = require("../data/activity.js");
|
|
45
|
+
var import_activity_row = require("./activity-row.js");
|
|
46
|
+
var import_cn = require("../utils/cn.js");
|
|
47
|
+
async function fetchAnnouncements() {
|
|
48
|
+
const res = await fetch("/api/announcements");
|
|
49
|
+
if (!res.ok) return [];
|
|
50
|
+
return res.json();
|
|
51
|
+
}
|
|
52
|
+
function AnnouncementsBanner({ announcements }) {
|
|
53
|
+
const pinned = announcements.filter((a) => a.pinned);
|
|
54
|
+
if (pinned.length === 0) return null;
|
|
55
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-2", children: pinned.map((ann) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
56
|
+
import_link.default,
|
|
57
|
+
{
|
|
58
|
+
href: ann.href,
|
|
59
|
+
className: "flex items-start gap-3 rounded-xl border border-brand-purple/20 bg-brand-purple/5 px-4 py-3 hover:bg-brand-purple/10 transition-colors group",
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-8 w-8 rounded-lg bg-brand-purple/10 flex items-center justify-center shrink-0 mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Megaphone, { className: "h-3.5 w-3.5 text-brand-purple" }) }),
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5 mb-0.5", children: [
|
|
64
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Pin, { className: "h-2.5 w-2.5 text-brand-purple/60" }),
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-brand-purple/60", children: "Announcement" })
|
|
66
|
+
] }),
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold leading-snug", children: ann.title }),
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground mt-0.5 truncate", children: ann.body })
|
|
69
|
+
] }),
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowRight, { className: "h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors shrink-0 mt-1" })
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
ann.id
|
|
74
|
+
)) });
|
|
75
|
+
}
|
|
76
|
+
const PAGE_SIZE = 30;
|
|
77
|
+
function ActivitiesFeed({ getClient }) {
|
|
78
|
+
const [page, setPage] = (0, import_react.useState)(1);
|
|
79
|
+
const [typeFilter, setTypeFilter] = (0, import_react.useState)("");
|
|
80
|
+
const [allActivities, setAllActivities] = (0, import_react.useState)([]);
|
|
81
|
+
const { data: announcements = [] } = (0, import_swr.default)(
|
|
82
|
+
"announcements",
|
|
83
|
+
fetchAnnouncements,
|
|
84
|
+
{ revalidateOnFocus: false }
|
|
85
|
+
);
|
|
86
|
+
const prevType = (0, import_react.useRef)(typeFilter);
|
|
87
|
+
(0, import_react.useEffect)(() => {
|
|
88
|
+
if (prevType.current !== typeFilter) {
|
|
89
|
+
prevType.current = typeFilter;
|
|
90
|
+
setPage(1);
|
|
91
|
+
setAllActivities([]);
|
|
92
|
+
}
|
|
93
|
+
}, [typeFilter]);
|
|
94
|
+
const { activities, meta, isLoading } = (0, import_use_activities.useActivities)(getClient, {
|
|
95
|
+
limit: PAGE_SIZE,
|
|
96
|
+
page,
|
|
97
|
+
type: typeFilter || void 0
|
|
98
|
+
});
|
|
99
|
+
(0, import_react.useEffect)(() => {
|
|
100
|
+
if (isLoading) return;
|
|
101
|
+
if (page === 1) {
|
|
102
|
+
setAllActivities(activities);
|
|
103
|
+
} else {
|
|
104
|
+
setAllActivities((prev) => {
|
|
105
|
+
const existing = new Set(
|
|
106
|
+
prev.map((a) => `${a.txHash}-${a.type}-${a.nftTokenId ?? ""}`)
|
|
107
|
+
);
|
|
108
|
+
const newItems = activities.filter(
|
|
109
|
+
(a) => !existing.has(`${a.txHash}-${a.type}-${a.nftTokenId ?? ""}`)
|
|
110
|
+
);
|
|
111
|
+
return newItems.length > 0 ? [...prev, ...newItems] : prev;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}, [activities, isLoading, page]);
|
|
115
|
+
const pageActors = allActivities.map((a) => a.offerer ?? a.fulfiller ?? (a.type === "mint" ? a.to : a.from)).filter((a) => Boolean(a));
|
|
116
|
+
const { data: actorLevels } = (0, import_use_rewards.useRewardsBatch)(getClient, pageActors);
|
|
117
|
+
const isInitialLoading = isLoading && allActivities.length === 0;
|
|
118
|
+
const isLoadingMore = isLoading && allActivities.length > 0;
|
|
119
|
+
const hasMore = meta?.total != null ? allActivities.length < meta.total : false;
|
|
120
|
+
const total = meta?.total ?? null;
|
|
121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-5", children: [
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnnouncementsBanner, { announcements }),
|
|
123
|
+
total != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
125
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" }),
|
|
126
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold text-foreground tabular-nums", children: total.toLocaleString() }),
|
|
127
|
+
typeFilter ? `${typeFilter} events` : "total events"
|
|
128
|
+
] }),
|
|
129
|
+
typeFilter && allActivities.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground/40", children: "\xB7" }),
|
|
131
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
132
|
+
allActivities.length.toLocaleString(),
|
|
133
|
+
" loaded"
|
|
134
|
+
] })
|
|
135
|
+
] })
|
|
136
|
+
] }),
|
|
137
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-2", children: import_activity.TYPE_FILTERS.map((f) => {
|
|
138
|
+
const typeConfig = f.value ? import_activity.ACTIVITY_TYPE_CONFIG[f.value] : null;
|
|
139
|
+
const Icon = typeConfig?.icon;
|
|
140
|
+
const isActive = typeFilter === f.value;
|
|
141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
142
|
+
"button",
|
|
143
|
+
{
|
|
144
|
+
onClick: () => setTypeFilter(f.value),
|
|
145
|
+
className: (0, import_cn.cn)(
|
|
146
|
+
"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-all font-medium",
|
|
147
|
+
isActive ? "border-primary bg-primary/10 text-primary shadow-sm" : "border-border text-muted-foreground hover:border-primary/40 hover:text-foreground hover:bg-muted/50"
|
|
148
|
+
),
|
|
149
|
+
children: [
|
|
150
|
+
Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
151
|
+
Icon,
|
|
152
|
+
{
|
|
153
|
+
className: (0, import_cn.cn)(
|
|
154
|
+
"h-3 w-3",
|
|
155
|
+
isActive ? typeConfig?.colorClass : ""
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
f.label
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
f.value
|
|
163
|
+
);
|
|
164
|
+
}) }),
|
|
165
|
+
isInitialLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "divide-y divide-border/50 rounded-xl border border-border overflow-hidden", children: Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 px-4 py-3.5 bg-card", children: [
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-8 w-8 rounded-lg shrink-0" }),
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-9 w-9 rounded-md shrink-0" }),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 space-y-2", children: [
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-3.5 w-40" }),
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-2.5 w-24" })
|
|
171
|
+
] }),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
173
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1 text-right", children: [
|
|
174
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-4 w-16" }),
|
|
175
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-2.5 w-8" })
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_skeleton.Skeleton, { className: "h-2.5 w-12 hidden sm:block" })
|
|
178
|
+
] })
|
|
179
|
+
] }, i)) }) : allActivities.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "py-20 flex flex-col items-center gap-3 text-center", children: [
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-12 w-12 rounded-full bg-muted flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Zap, { className: "h-5 w-5 text-muted-foreground" }) }),
|
|
181
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-muted-foreground", children: typeFilter ? `No ${typeFilter} events yet.` : "No activity yet." })
|
|
182
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
|
|
183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "divide-y divide-border/50 rounded-xl border border-border overflow-hidden", children: allActivities.map((activity, i) => {
|
|
184
|
+
const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === "mint" ? activity.to : activity.from);
|
|
185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
186
|
+
import_activity_row.ActivityRow,
|
|
187
|
+
{
|
|
188
|
+
activity,
|
|
189
|
+
showActor: true,
|
|
190
|
+
showExplorer: true,
|
|
191
|
+
actorLevel: actor ? actorLevels?.get(actor) : void 0
|
|
192
|
+
},
|
|
193
|
+
`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`
|
|
194
|
+
);
|
|
195
|
+
}) }),
|
|
196
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
197
|
+
import_load_more_sentinel.LoadMoreSentinel,
|
|
198
|
+
{
|
|
199
|
+
hasMore,
|
|
200
|
+
isLoading: isLoadingMore,
|
|
201
|
+
onLoadMore: () => setPage((p) => p + 1)
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
] })
|
|
205
|
+
] });
|
|
206
|
+
}
|
|
207
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
208
|
+
0 && (module.exports = {
|
|
209
|
+
ActivitiesFeed
|
|
210
|
+
});
|
|
211
|
+
//# sourceMappingURL=activities-feed.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/activities-feed.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport Link from \"next/link\";\nimport { useActivities } from \"../utils/use-activities.js\";\nimport { useRewardsBatch } from \"../utils/use-rewards.js\";\nimport type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\nimport type { MedialaneClient } from \"@medialane/sdk/starknet\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { Zap, Megaphone, ArrowRight, Pin } from \"lucide-react\";\nimport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"../data/activity.js\";\nimport { ActivityRow } from \"./activity-row.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { Announcement } from \"../data/notification.js\";\n\nasync function fetchAnnouncements(): Promise<Announcement[]> {\n const res = await fetch(\"/api/announcements\");\n if (!res.ok) return [];\n return res.json();\n}\n\nfunction AnnouncementsBanner({ announcements }: { announcements: Announcement[] }) {\n const pinned = announcements.filter((a) => a.pinned);\n if (pinned.length === 0) return null;\n return (\n <div className=\"space-y-2\">\n {pinned.map((ann) => (\n <Link\n key={ann.id}\n href={ann.href}\n className=\"flex items-start gap-3 rounded-xl border border-brand-purple/20 bg-brand-purple/5 px-4 py-3 hover:bg-brand-purple/10 transition-colors group\"\n >\n <div className=\"h-8 w-8 rounded-lg bg-brand-purple/10 flex items-center justify-center shrink-0 mt-0.5\">\n <Megaphone className=\"h-3.5 w-3.5 text-brand-purple\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5 mb-0.5\">\n <Pin className=\"h-2.5 w-2.5 text-brand-purple/60\" />\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-brand-purple/60\">Announcement</span>\n </div>\n <p className=\"text-sm font-semibold leading-snug\">{ann.title}</p>\n <p className=\"text-xs text-muted-foreground mt-0.5 truncate\">{ann.body}</p>\n </div>\n <ArrowRight className=\"h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors shrink-0 mt-1\" />\n </Link>\n ))}\n </div>\n );\n}\n\nconst PAGE_SIZE = 30;\n\nexport interface ActivitiesFeedProps {\n getClient: () => MedialaneClient;\n}\n\nexport function ActivitiesFeed({ getClient }: ActivitiesFeedProps) {\n const [page, setPage] = useState(1);\n const [typeFilter, setTypeFilter] = useState(\"\");\n const [allActivities, setAllActivities] = useState<ApiActivity[]>([]);\n const { data: announcements = [] } = useSWR<Announcement[]>(\n \"announcements\",\n fetchAnnouncements,\n { revalidateOnFocus: false }\n );\n\n const prevType = useRef(typeFilter);\n useEffect(() => {\n if (prevType.current !== typeFilter) {\n prevType.current = typeFilter;\n setPage(1);\n setAllActivities([]);\n }\n }, [typeFilter]);\n\n const { activities, meta, isLoading } = useActivities(getClient, {\n limit: PAGE_SIZE,\n page,\n type: (typeFilter as ApiActivitiesQuery[\"type\"]) || undefined,\n });\n\n useEffect(() => {\n if (isLoading) return;\n if (page === 1) {\n setAllActivities(activities);\n } else {\n setAllActivities((prev) => {\n const existing = new Set(\n prev.map((a) => `${a.txHash}-${a.type}-${a.nftTokenId ?? \"\"}`)\n );\n const newItems = activities.filter(\n (a) => !existing.has(`${a.txHash}-${a.type}-${a.nftTokenId ?? \"\"}`)\n );\n return newItems.length > 0 ? [...prev, ...newItems] : prev;\n });\n }\n }, [activities, isLoading, page]);\n\n const pageActors = allActivities\n .map((a) => a.offerer ?? a.fulfiller ?? (a.type === \"mint\" ? a.to : a.from))\n .filter((a): a is string => Boolean(a));\n const { data: actorLevels } = useRewardsBatch(getClient, pageActors);\n\n const isInitialLoading = isLoading && allActivities.length === 0;\n const isLoadingMore = isLoading && allActivities.length > 0;\n const hasMore = meta?.total != null ? allActivities.length < meta.total : false;\n const total = meta?.total ?? null;\n\n return (\n <div className=\"space-y-5\">\n <AnnouncementsBanner announcements={announcements} />\n\n {total != null && (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"font-semibold text-foreground tabular-nums\">\n {total.toLocaleString()}\n </span>\n {typeFilter ? `${typeFilter} events` : \"total events\"}\n </span>\n {typeFilter && allActivities.length > 0 && (\n <>\n <span className=\"text-muted-foreground/40\">·</span>\n <span>{allActivities.length.toLocaleString()} loaded</span>\n </>\n )}\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {TYPE_FILTERS.map((f) => {\n const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;\n const Icon = typeConfig?.icon;\n const isActive = typeFilter === f.value;\n return (\n <button\n key={f.value}\n onClick={() => setTypeFilter(f.value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-all font-medium\",\n isActive\n ? \"border-primary bg-primary/10 text-primary shadow-sm\"\n : \"border-border text-muted-foreground hover:border-primary/40 hover:text-foreground hover:bg-muted/50\"\n )}\n >\n {Icon && (\n <Icon\n className={cn(\n \"h-3 w-3\",\n isActive ? typeConfig?.colorClass : \"\"\n )}\n />\n )}\n {f.label}\n </button>\n );\n })}\n </div>\n\n {isInitialLoading ? (\n <div className=\"divide-y divide-border/50 rounded-xl border border-border overflow-hidden\">\n {Array.from({ length: 10 }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 px-4 py-3.5 bg-card\">\n <Skeleton className=\"h-8 w-8 rounded-lg shrink-0\" />\n <Skeleton className=\"h-9 w-9 rounded-md shrink-0\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-3.5 w-40\" />\n <Skeleton className=\"h-2.5 w-24\" />\n </div>\n <div className=\"flex items-center gap-2.5\">\n <div className=\"space-y-1 text-right\">\n <Skeleton className=\"h-4 w-16\" />\n <Skeleton className=\"h-2.5 w-8\" />\n </div>\n <Skeleton className=\"h-2.5 w-12 hidden sm:block\" />\n </div>\n </div>\n ))}\n </div>\n ) : allActivities.length === 0 ? (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <div className=\"h-12 w-12 rounded-full bg-muted flex items-center justify-center\">\n <Zap className=\"h-5 w-5 text-muted-foreground\" />\n </div>\n <p className=\"text-muted-foreground\">\n {typeFilter ? `No ${typeFilter} events yet.` : \"No activity yet.\"}\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <div className=\"divide-y divide-border/50 rounded-xl border border-border overflow-hidden\">\n {allActivities.map((activity, i) => {\n const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === \"mint\" ? activity.to : activity.from);\n return (\n <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\n actorLevel={actor ? actorLevels?.get(actor) : undefined}\n />\n );\n })}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoadingMore}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["Link","useSWR"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MedialaneClient } from '@medialane/sdk/starknet';
|
|
3
|
+
|
|
4
|
+
interface ActivitiesFeedProps {
|
|
5
|
+
getClient: () => MedialaneClient;
|
|
6
|
+
}
|
|
7
|
+
declare function ActivitiesFeed({ getClient }: ActivitiesFeedProps): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { ActivitiesFeed, type ActivitiesFeedProps };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { MedialaneClient } from '@medialane/sdk/starknet';
|
|
3
|
+
|
|
4
|
+
interface ActivitiesFeedProps {
|
|
5
|
+
getClient: () => MedialaneClient;
|
|
6
|
+
}
|
|
7
|
+
declare function ActivitiesFeed({ getClient }: ActivitiesFeedProps): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { ActivitiesFeed, type ActivitiesFeedProps };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect, useRef } from "react";
|
|
4
|
+
import useSWR from "swr";
|
|
5
|
+
import Link from "next/link";
|
|
6
|
+
import { useActivities } from "../utils/use-activities.js";
|
|
7
|
+
import { useRewardsBatch } from "../utils/use-rewards.js";
|
|
8
|
+
import { Skeleton } from "./skeleton.js";
|
|
9
|
+
import { LoadMoreSentinel } from "./load-more-sentinel.js";
|
|
10
|
+
import { Zap, Megaphone, ArrowRight, Pin } from "lucide-react";
|
|
11
|
+
import { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from "../data/activity.js";
|
|
12
|
+
import { ActivityRow } from "./activity-row.js";
|
|
13
|
+
import { cn } from "../utils/cn.js";
|
|
14
|
+
async function fetchAnnouncements() {
|
|
15
|
+
const res = await fetch("/api/announcements");
|
|
16
|
+
if (!res.ok) return [];
|
|
17
|
+
return res.json();
|
|
18
|
+
}
|
|
19
|
+
function AnnouncementsBanner({ announcements }) {
|
|
20
|
+
const pinned = announcements.filter((a) => a.pinned);
|
|
21
|
+
if (pinned.length === 0) return null;
|
|
22
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: pinned.map((ann) => /* @__PURE__ */ jsxs(
|
|
23
|
+
Link,
|
|
24
|
+
{
|
|
25
|
+
href: ann.href,
|
|
26
|
+
className: "flex items-start gap-3 rounded-xl border border-brand-purple/20 bg-brand-purple/5 px-4 py-3 hover:bg-brand-purple/10 transition-colors group",
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 rounded-lg bg-brand-purple/10 flex items-center justify-center shrink-0 mt-0.5", children: /* @__PURE__ */ jsx(Megaphone, { className: "h-3.5 w-3.5 text-brand-purple" }) }),
|
|
29
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-0.5", children: [
|
|
31
|
+
/* @__PURE__ */ jsx(Pin, { className: "h-2.5 w-2.5 text-brand-purple/60" }),
|
|
32
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold uppercase tracking-widest text-brand-purple/60", children: "Announcement" })
|
|
33
|
+
] }),
|
|
34
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-snug", children: ann.title }),
|
|
35
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5 truncate", children: ann.body })
|
|
36
|
+
] }),
|
|
37
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors shrink-0 mt-1" })
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
ann.id
|
|
41
|
+
)) });
|
|
42
|
+
}
|
|
43
|
+
const PAGE_SIZE = 30;
|
|
44
|
+
function ActivitiesFeed({ getClient }) {
|
|
45
|
+
const [page, setPage] = useState(1);
|
|
46
|
+
const [typeFilter, setTypeFilter] = useState("");
|
|
47
|
+
const [allActivities, setAllActivities] = useState([]);
|
|
48
|
+
const { data: announcements = [] } = useSWR(
|
|
49
|
+
"announcements",
|
|
50
|
+
fetchAnnouncements,
|
|
51
|
+
{ revalidateOnFocus: false }
|
|
52
|
+
);
|
|
53
|
+
const prevType = useRef(typeFilter);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (prevType.current !== typeFilter) {
|
|
56
|
+
prevType.current = typeFilter;
|
|
57
|
+
setPage(1);
|
|
58
|
+
setAllActivities([]);
|
|
59
|
+
}
|
|
60
|
+
}, [typeFilter]);
|
|
61
|
+
const { activities, meta, isLoading } = useActivities(getClient, {
|
|
62
|
+
limit: PAGE_SIZE,
|
|
63
|
+
page,
|
|
64
|
+
type: typeFilter || void 0
|
|
65
|
+
});
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (isLoading) return;
|
|
68
|
+
if (page === 1) {
|
|
69
|
+
setAllActivities(activities);
|
|
70
|
+
} else {
|
|
71
|
+
setAllActivities((prev) => {
|
|
72
|
+
const existing = new Set(
|
|
73
|
+
prev.map((a) => `${a.txHash}-${a.type}-${a.nftTokenId ?? ""}`)
|
|
74
|
+
);
|
|
75
|
+
const newItems = activities.filter(
|
|
76
|
+
(a) => !existing.has(`${a.txHash}-${a.type}-${a.nftTokenId ?? ""}`)
|
|
77
|
+
);
|
|
78
|
+
return newItems.length > 0 ? [...prev, ...newItems] : prev;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}, [activities, isLoading, page]);
|
|
82
|
+
const pageActors = allActivities.map((a) => a.offerer ?? a.fulfiller ?? (a.type === "mint" ? a.to : a.from)).filter((a) => Boolean(a));
|
|
83
|
+
const { data: actorLevels } = useRewardsBatch(getClient, pageActors);
|
|
84
|
+
const isInitialLoading = isLoading && allActivities.length === 0;
|
|
85
|
+
const isLoadingMore = isLoading && allActivities.length > 0;
|
|
86
|
+
const hasMore = meta?.total != null ? allActivities.length < meta.total : false;
|
|
87
|
+
const total = meta?.total ?? null;
|
|
88
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
89
|
+
/* @__PURE__ */ jsx(AnnouncementsBanner, { announcements }),
|
|
90
|
+
total != null && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
91
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
92
|
+
/* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse" }),
|
|
93
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground tabular-nums", children: total.toLocaleString() }),
|
|
94
|
+
typeFilter ? `${typeFilter} events` : "total events"
|
|
95
|
+
] }),
|
|
96
|
+
typeFilter && allActivities.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
97
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
|
|
98
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
99
|
+
allActivities.length.toLocaleString(),
|
|
100
|
+
" loaded"
|
|
101
|
+
] })
|
|
102
|
+
] })
|
|
103
|
+
] }),
|
|
104
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: TYPE_FILTERS.map((f) => {
|
|
105
|
+
const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;
|
|
106
|
+
const Icon = typeConfig?.icon;
|
|
107
|
+
const isActive = typeFilter === f.value;
|
|
108
|
+
return /* @__PURE__ */ jsxs(
|
|
109
|
+
"button",
|
|
110
|
+
{
|
|
111
|
+
onClick: () => setTypeFilter(f.value),
|
|
112
|
+
className: cn(
|
|
113
|
+
"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-all font-medium",
|
|
114
|
+
isActive ? "border-primary bg-primary/10 text-primary shadow-sm" : "border-border text-muted-foreground hover:border-primary/40 hover:text-foreground hover:bg-muted/50"
|
|
115
|
+
),
|
|
116
|
+
children: [
|
|
117
|
+
Icon && /* @__PURE__ */ jsx(
|
|
118
|
+
Icon,
|
|
119
|
+
{
|
|
120
|
+
className: cn(
|
|
121
|
+
"h-3 w-3",
|
|
122
|
+
isActive ? typeConfig?.colorClass : ""
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
f.label
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
f.value
|
|
130
|
+
);
|
|
131
|
+
}) }),
|
|
132
|
+
isInitialLoading ? /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/50 rounded-xl border border-border overflow-hidden", children: Array.from({ length: 10 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-3.5 bg-card", children: [
|
|
133
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-8 rounded-lg shrink-0" }),
|
|
134
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-9 rounded-md shrink-0" }),
|
|
135
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
136
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-40" }),
|
|
137
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-24" })
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1 text-right", children: [
|
|
141
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
|
|
142
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-8" })
|
|
143
|
+
] }),
|
|
144
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-12 hidden sm:block" })
|
|
145
|
+
] })
|
|
146
|
+
] }, i)) }) : allActivities.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "py-20 flex flex-col items-center gap-3 text-center", children: [
|
|
147
|
+
/* @__PURE__ */ jsx("div", { className: "h-12 w-12 rounded-full bg-muted flex items-center justify-center", children: /* @__PURE__ */ jsx(Zap, { className: "h-5 w-5 text-muted-foreground" }) }),
|
|
148
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: typeFilter ? `No ${typeFilter} events yet.` : "No activity yet." })
|
|
149
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
150
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y divide-border/50 rounded-xl border border-border overflow-hidden", children: allActivities.map((activity, i) => {
|
|
151
|
+
const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === "mint" ? activity.to : activity.from);
|
|
152
|
+
return /* @__PURE__ */ jsx(
|
|
153
|
+
ActivityRow,
|
|
154
|
+
{
|
|
155
|
+
activity,
|
|
156
|
+
showActor: true,
|
|
157
|
+
showExplorer: true,
|
|
158
|
+
actorLevel: actor ? actorLevels?.get(actor) : void 0
|
|
159
|
+
},
|
|
160
|
+
`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`
|
|
161
|
+
);
|
|
162
|
+
}) }),
|
|
163
|
+
/* @__PURE__ */ jsx(
|
|
164
|
+
LoadMoreSentinel,
|
|
165
|
+
{
|
|
166
|
+
hasMore,
|
|
167
|
+
isLoading: isLoadingMore,
|
|
168
|
+
onLoadMore: () => setPage((p) => p + 1)
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
] })
|
|
172
|
+
] });
|
|
173
|
+
}
|
|
174
|
+
export {
|
|
175
|
+
ActivitiesFeed
|
|
176
|
+
};
|
|
177
|
+
//# sourceMappingURL=activities-feed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/activities-feed.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport useSWR from \"swr\";\nimport Link from \"next/link\";\nimport { useActivities } from \"../utils/use-activities.js\";\nimport { useRewardsBatch } from \"../utils/use-rewards.js\";\nimport type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\nimport type { MedialaneClient } from \"@medialane/sdk/starknet\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { Zap, Megaphone, ArrowRight, Pin } from \"lucide-react\";\nimport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"../data/activity.js\";\nimport { ActivityRow } from \"./activity-row.js\";\nimport { cn } from \"../utils/cn.js\";\nimport type { Announcement } from \"../data/notification.js\";\n\nasync function fetchAnnouncements(): Promise<Announcement[]> {\n const res = await fetch(\"/api/announcements\");\n if (!res.ok) return [];\n return res.json();\n}\n\nfunction AnnouncementsBanner({ announcements }: { announcements: Announcement[] }) {\n const pinned = announcements.filter((a) => a.pinned);\n if (pinned.length === 0) return null;\n return (\n <div className=\"space-y-2\">\n {pinned.map((ann) => (\n <Link\n key={ann.id}\n href={ann.href}\n className=\"flex items-start gap-3 rounded-xl border border-brand-purple/20 bg-brand-purple/5 px-4 py-3 hover:bg-brand-purple/10 transition-colors group\"\n >\n <div className=\"h-8 w-8 rounded-lg bg-brand-purple/10 flex items-center justify-center shrink-0 mt-0.5\">\n <Megaphone className=\"h-3.5 w-3.5 text-brand-purple\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-1.5 mb-0.5\">\n <Pin className=\"h-2.5 w-2.5 text-brand-purple/60\" />\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-brand-purple/60\">Announcement</span>\n </div>\n <p className=\"text-sm font-semibold leading-snug\">{ann.title}</p>\n <p className=\"text-xs text-muted-foreground mt-0.5 truncate\">{ann.body}</p>\n </div>\n <ArrowRight className=\"h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors shrink-0 mt-1\" />\n </Link>\n ))}\n </div>\n );\n}\n\nconst PAGE_SIZE = 30;\n\nexport interface ActivitiesFeedProps {\n getClient: () => MedialaneClient;\n}\n\nexport function ActivitiesFeed({ getClient }: ActivitiesFeedProps) {\n const [page, setPage] = useState(1);\n const [typeFilter, setTypeFilter] = useState(\"\");\n const [allActivities, setAllActivities] = useState<ApiActivity[]>([]);\n const { data: announcements = [] } = useSWR<Announcement[]>(\n \"announcements\",\n fetchAnnouncements,\n { revalidateOnFocus: false }\n );\n\n const prevType = useRef(typeFilter);\n useEffect(() => {\n if (prevType.current !== typeFilter) {\n prevType.current = typeFilter;\n setPage(1);\n setAllActivities([]);\n }\n }, [typeFilter]);\n\n const { activities, meta, isLoading } = useActivities(getClient, {\n limit: PAGE_SIZE,\n page,\n type: (typeFilter as ApiActivitiesQuery[\"type\"]) || undefined,\n });\n\n useEffect(() => {\n if (isLoading) return;\n if (page === 1) {\n setAllActivities(activities);\n } else {\n setAllActivities((prev) => {\n const existing = new Set(\n prev.map((a) => `${a.txHash}-${a.type}-${a.nftTokenId ?? \"\"}`)\n );\n const newItems = activities.filter(\n (a) => !existing.has(`${a.txHash}-${a.type}-${a.nftTokenId ?? \"\"}`)\n );\n return newItems.length > 0 ? [...prev, ...newItems] : prev;\n });\n }\n }, [activities, isLoading, page]);\n\n const pageActors = allActivities\n .map((a) => a.offerer ?? a.fulfiller ?? (a.type === \"mint\" ? a.to : a.from))\n .filter((a): a is string => Boolean(a));\n const { data: actorLevels } = useRewardsBatch(getClient, pageActors);\n\n const isInitialLoading = isLoading && allActivities.length === 0;\n const isLoadingMore = isLoading && allActivities.length > 0;\n const hasMore = meta?.total != null ? allActivities.length < meta.total : false;\n const total = meta?.total ?? null;\n\n return (\n <div className=\"space-y-5\">\n <AnnouncementsBanner announcements={announcements} />\n\n {total != null && (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <span className=\"flex items-center gap-1.5\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-emerald-500 animate-pulse\" />\n <span className=\"font-semibold text-foreground tabular-nums\">\n {total.toLocaleString()}\n </span>\n {typeFilter ? `${typeFilter} events` : \"total events\"}\n </span>\n {typeFilter && allActivities.length > 0 && (\n <>\n <span className=\"text-muted-foreground/40\">·</span>\n <span>{allActivities.length.toLocaleString()} loaded</span>\n </>\n )}\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {TYPE_FILTERS.map((f) => {\n const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;\n const Icon = typeConfig?.icon;\n const isActive = typeFilter === f.value;\n return (\n <button\n key={f.value}\n onClick={() => setTypeFilter(f.value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-all font-medium\",\n isActive\n ? \"border-primary bg-primary/10 text-primary shadow-sm\"\n : \"border-border text-muted-foreground hover:border-primary/40 hover:text-foreground hover:bg-muted/50\"\n )}\n >\n {Icon && (\n <Icon\n className={cn(\n \"h-3 w-3\",\n isActive ? typeConfig?.colorClass : \"\"\n )}\n />\n )}\n {f.label}\n </button>\n );\n })}\n </div>\n\n {isInitialLoading ? (\n <div className=\"divide-y divide-border/50 rounded-xl border border-border overflow-hidden\">\n {Array.from({ length: 10 }).map((_, i) => (\n <div key={i} className=\"flex items-center gap-3 px-4 py-3.5 bg-card\">\n <Skeleton className=\"h-8 w-8 rounded-lg shrink-0\" />\n <Skeleton className=\"h-9 w-9 rounded-md shrink-0\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-3.5 w-40\" />\n <Skeleton className=\"h-2.5 w-24\" />\n </div>\n <div className=\"flex items-center gap-2.5\">\n <div className=\"space-y-1 text-right\">\n <Skeleton className=\"h-4 w-16\" />\n <Skeleton className=\"h-2.5 w-8\" />\n </div>\n <Skeleton className=\"h-2.5 w-12 hidden sm:block\" />\n </div>\n </div>\n ))}\n </div>\n ) : allActivities.length === 0 ? (\n <div className=\"py-20 flex flex-col items-center gap-3 text-center\">\n <div className=\"h-12 w-12 rounded-full bg-muted flex items-center justify-center\">\n <Zap className=\"h-5 w-5 text-muted-foreground\" />\n </div>\n <p className=\"text-muted-foreground\">\n {typeFilter ? `No ${typeFilter} events yet.` : \"No activity yet.\"}\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <div className=\"divide-y divide-border/50 rounded-xl border border-border overflow-hidden\">\n {allActivities.map((activity, i) => {\n const actor = activity.offerer ?? activity.fulfiller ?? (activity.type === \"mint\" ? activity.to : activity.from);\n return (\n <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\n actorLevel={actor ? actorLevels?.get(actor) : undefined}\n />\n );\n })}\n </div>\n\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoadingMore}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";AAmCY,SAyFA,UAzFA,KAGA,YAHA;AAjCZ,SAAS,UAAU,WAAW,cAAc;AAC5C,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAGhC,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AACjC,SAAS,KAAK,WAAW,YAAY,WAAW;AAChD,SAAS,sBAAsB,oBAAoB;AACnD,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AAGnB,eAAe,qBAA8C;AAC3D,QAAM,MAAM,MAAM,MAAM,oBAAoB;AAC5C,MAAI,CAAC,IAAI,GAAI,QAAO,CAAC;AACrB,SAAO,IAAI,KAAK;AAClB;AAEA,SAAS,oBAAoB,EAAE,cAAc,GAAsC;AACjF,QAAM,SAAS,cAAc,OAAO,CAAC,MAAM,EAAE,MAAM;AACnD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SACE,oBAAC,SAAI,WAAU,aACZ,iBAAO,IAAI,CAAC,QACX;AAAA,IAAC;AAAA;AAAA,MAEC,MAAM,IAAI;AAAA,MACV,WAAU;AAAA,MAEV;AAAA,4BAAC,SAAI,WAAU,0FACb,8BAAC,aAAU,WAAU,iCAAgC,GACvD;AAAA,QACA,qBAAC,SAAI,WAAU,kBACb;AAAA,+BAAC,SAAI,WAAU,oCACb;AAAA,gCAAC,OAAI,WAAU,oCAAmC;AAAA,YAClD,oBAAC,UAAK,WAAU,wEAAuE,0BAAY;AAAA,aACrG;AAAA,UACA,oBAAC,OAAE,WAAU,sCAAsC,cAAI,OAAM;AAAA,UAC7D,oBAAC,OAAE,WAAU,iDAAiD,cAAI,MAAK;AAAA,WACzE;AAAA,QACA,oBAAC,cAAW,WAAU,6FAA4F;AAAA;AAAA;AAAA,IAf7G,IAAI;AAAA,EAgBX,CACD,GACH;AAEJ;AAEA,MAAM,YAAY;AAMX,SAAS,eAAe,EAAE,UAAU,GAAwB;AACjE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,CAAC;AAClC,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,EAAE;AAC/C,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB,CAAC,CAAC;AACpE,QAAM,EAAE,MAAM,gBAAgB,CAAC,EAAE,IAAI;AAAA,IACnC;AAAA,IACA;AAAA,IACA,EAAE,mBAAmB,MAAM;AAAA,EAC7B;AAEA,QAAM,WAAW,OAAO,UAAU;AAClC,YAAU,MAAM;AACd,QAAI,SAAS,YAAY,YAAY;AACnC,eAAS,UAAU;AACnB,cAAQ,CAAC;AACT,uBAAiB,CAAC,CAAC;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,QAAM,EAAE,YAAY,MAAM,UAAU,IAAI,cAAc,WAAW;AAAA,IAC/D,OAAO;AAAA,IACP;AAAA,IACA,MAAO,cAA6C;AAAA,EACtD,CAAC;AAED,YAAU,MAAM;AACd,QAAI,UAAW;AACf,QAAI,SAAS,GAAG;AACd,uBAAiB,UAAU;AAAA,IAC7B,OAAO;AACL,uBAAiB,CAAC,SAAS;AACzB,cAAM,WAAW,IAAI;AAAA,UACnB,KAAK,IAAI,CAAC,MAAM,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,IAAI,EAAE,cAAc,EAAE,EAAE;AAAA,QAC/D;AACA,cAAM,WAAW,WAAW;AAAA,UAC1B,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,IAAI,EAAE,cAAc,EAAE,EAAE;AAAA,QACpE;AACA,eAAO,SAAS,SAAS,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,IAAI;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,YAAY,WAAW,IAAI,CAAC;AAEhC,QAAM,aAAa,cAChB,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,SAAS,EAAE,KAAK,EAAE,KAAK,EAC1E,OAAO,CAAC,MAAmB,QAAQ,CAAC,CAAC;AACxC,QAAM,EAAE,MAAM,YAAY,IAAI,gBAAgB,WAAW,UAAU;AAEnE,QAAM,mBAAmB,aAAa,cAAc,WAAW;AAC/D,QAAM,gBAAgB,aAAa,cAAc,SAAS;AAC1D,QAAM,UAAU,MAAM,SAAS,OAAO,cAAc,SAAS,KAAK,QAAQ;AAC1E,QAAM,QAAQ,MAAM,SAAS;AAE7B,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,uBAAoB,eAA8B;AAAA,IAElD,SAAS,QACR,qBAAC,SAAI,WAAU,yDACb;AAAA,2BAAC,UAAK,WAAU,6BACd;AAAA,4BAAC,UAAK,WAAU,yDAAwD;AAAA,QACxE,oBAAC,UAAK,WAAU,8CACb,gBAAM,eAAe,GACxB;AAAA,QACC,aAAa,GAAG,UAAU,YAAY;AAAA,SACzC;AAAA,MACC,cAAc,cAAc,SAAS,KACpC,iCACE;AAAA,4BAAC,UAAK,WAAU,4BAA2B,kBAAC;AAAA,QAC5C,qBAAC,UAAM;AAAA,wBAAc,OAAO,eAAe;AAAA,UAAE;AAAA,WAAO;AAAA,SACtD;AAAA,OAEJ;AAAA,IAGF,oBAAC,SAAI,WAAU,wBACZ,uBAAa,IAAI,CAAC,MAAM;AACvB,YAAM,aAAa,EAAE,QAAQ,qBAAqB,EAAE,KAAK,IAAI;AAC7D,YAAM,OAAO,YAAY;AACzB,YAAM,WAAW,eAAe,EAAE;AAClC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM,cAAc,EAAE,KAAK;AAAA,UACpC,WAAW;AAAA,YACT;AAAA,YACA,WACI,wDACA;AAAA,UACN;AAAA,UAEC;AAAA,oBACC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,WAAW,YAAY,aAAa;AAAA,gBACtC;AAAA;AAAA,YACF;AAAA,YAED,EAAE;AAAA;AAAA;AAAA,QAjBE,EAAE;AAAA,MAkBT;AAAA,IAEJ,CAAC,GACH;AAAA,IAEC,mBACC,oBAAC,SAAI,WAAU,6EACZ,gBAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,MAClC,qBAAC,SAAY,WAAU,+CACrB;AAAA,0BAAC,YAAS,WAAU,+BAA8B;AAAA,MAClD,oBAAC,YAAS,WAAU,+BAA8B;AAAA,MAClD,qBAAC,SAAI,WAAU,oBACb;AAAA,4BAAC,YAAS,WAAU,cAAa;AAAA,QACjC,oBAAC,YAAS,WAAU,cAAa;AAAA,SACnC;AAAA,MACA,qBAAC,SAAI,WAAU,6BACb;AAAA,6BAAC,SAAI,WAAU,wBACb;AAAA,8BAAC,YAAS,WAAU,YAAW;AAAA,UAC/B,oBAAC,YAAS,WAAU,aAAY;AAAA,WAClC;AAAA,QACA,oBAAC,YAAS,WAAU,8BAA6B;AAAA,SACnD;AAAA,SAbQ,CAcV,CACD,GACH,IACE,cAAc,WAAW,IAC3B,qBAAC,SAAI,WAAU,sDACb;AAAA,0BAAC,SAAI,WAAU,oEACb,8BAAC,OAAI,WAAU,iCAAgC,GACjD;AAAA,MACA,oBAAC,OAAE,WAAU,yBACV,uBAAa,MAAM,UAAU,iBAAiB,oBACjD;AAAA,OACF,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAI,WAAU,6EACZ,wBAAc,IAAI,CAAC,UAAU,MAAM;AAClC,cAAM,QAAQ,SAAS,WAAW,SAAS,cAAc,SAAS,SAAS,SAAS,SAAS,KAAK,SAAS;AAC3G,eACE;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,WAAS;AAAA,YACT,cAAY;AAAA,YACZ,YAAY,QAAQ,aAAa,IAAI,KAAK,IAAI;AAAA;AAAA,UAJzC,GAAG,SAAS,MAAM,IAAI,SAAS,IAAI,IAAI,SAAS,cAAc,CAAC;AAAA,QAKtE;AAAA,MAEJ,CAAC,GACH;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,WAAW;AAAA,UACX,YAAY,MAAM,QAAQ,CAAC,MAAM,IAAI,CAAC;AAAA;AAAA,MACxC;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "ghost" | "link" | "default" | "destructive" | "outline" | "secondary" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
7
|
size?: "icon" | "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "ghost" | "link" | "default" | "destructive" | "outline" | "secondary" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
7
|
size?: "icon" | "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -202,7 +202,8 @@ function FastMint(props) {
|
|
|
202
202
|
getUploadToken,
|
|
203
203
|
getSigner,
|
|
204
204
|
client,
|
|
205
|
-
provider
|
|
205
|
+
provider,
|
|
206
|
+
successFooter
|
|
206
207
|
} = props;
|
|
207
208
|
const [status, setStatus] = (0, import_react.useState)("idle");
|
|
208
209
|
const [errorMsg, setErrorMsg] = (0, import_react.useState)(null);
|
|
@@ -516,6 +517,7 @@ function FastMint(props) {
|
|
|
516
517
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
517
518
|
import_success_view.SuccessView,
|
|
518
519
|
{
|
|
520
|
+
footer: successFooter,
|
|
519
521
|
presentation,
|
|
520
522
|
previewImage: mediaKind === "image" ? mediaPreview : featurePreview,
|
|
521
523
|
name,
|