@medialane/ui 0.258.0 → 0.260.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.
Files changed (167) hide show
  1. package/dist/components/activities-feed.cjs +5 -1
  2. package/dist/components/activities-feed.cjs.map +1 -1
  3. package/dist/components/activities-feed.js +5 -1
  4. package/dist/components/activities-feed.js.map +1 -1
  5. package/dist/components/activity-feed-shell.cjs +3 -1
  6. package/dist/components/activity-feed-shell.cjs.map +1 -1
  7. package/dist/components/activity-feed-shell.js +3 -1
  8. package/dist/components/activity-feed-shell.js.map +1 -1
  9. package/dist/components/button.d.cts +1 -1
  10. package/dist/components/button.d.ts +1 -1
  11. package/dist/components/coins-explorer.cjs +5 -1
  12. package/dist/components/coins-explorer.cjs.map +1 -1
  13. package/dist/components/coins-explorer.js +6 -2
  14. package/dist/components/coins-explorer.js.map +1 -1
  15. package/dist/components/comments-section.cjs +7 -6
  16. package/dist/components/comments-section.cjs.map +1 -1
  17. package/dist/components/comments-section.js +7 -6
  18. package/dist/components/comments-section.js.map +1 -1
  19. package/dist/components/discover-community-section.cjs +5 -1
  20. package/dist/components/discover-community-section.cjs.map +1 -1
  21. package/dist/components/discover-community-section.js +5 -1
  22. package/dist/components/discover-community-section.js.map +1 -1
  23. package/dist/components/discover-feed-section.cjs +5 -1
  24. package/dist/components/discover-feed-section.cjs.map +1 -1
  25. package/dist/components/discover-feed-section.js +5 -1
  26. package/dist/components/discover-feed-section.js.map +1 -1
  27. package/dist/components/fast-mint/fast-mint.d.cts +2 -2
  28. package/dist/components/fast-mint/fast-mint.d.ts +2 -2
  29. package/dist/components/fast-mint/success-view.cjs +2 -2
  30. package/dist/components/fast-mint/success-view.cjs.map +1 -1
  31. package/dist/components/fast-mint/success-view.js +2 -2
  32. package/dist/components/fast-mint/success-view.js.map +1 -1
  33. package/dist/components/ip-type-page.cjs +3 -2
  34. package/dist/components/ip-type-page.cjs.map +1 -1
  35. package/dist/components/ip-type-page.js +3 -2
  36. package/dist/components/ip-type-page.js.map +1 -1
  37. package/dist/components/launchpad/coin-create.cjs +9 -7
  38. package/dist/components/launchpad/coin-create.cjs.map +1 -1
  39. package/dist/components/launchpad/coin-create.js +9 -7
  40. package/dist/components/launchpad/coin-create.js.map +1 -1
  41. package/dist/components/launchpad/collection-create-form.cjs +11 -14
  42. package/dist/components/launchpad/collection-create-form.cjs.map +1 -1
  43. package/dist/components/launchpad/collection-create-form.js +12 -15
  44. package/dist/components/launchpad/collection-create-form.js.map +1 -1
  45. package/dist/components/launchpad/collection-create-presets.cjs +8 -8
  46. package/dist/components/launchpad/collection-create-presets.cjs.map +1 -1
  47. package/dist/components/launchpad/collection-create-presets.d.cts +2 -1
  48. package/dist/components/launchpad/collection-create-presets.d.ts +2 -1
  49. package/dist/components/launchpad/collection-create-presets.js +8 -8
  50. package/dist/components/launchpad/collection-create-presets.js.map +1 -1
  51. package/dist/components/launchpad/edition-mint.cjs +9 -7
  52. package/dist/components/launchpad/edition-mint.cjs.map +1 -1
  53. package/dist/components/launchpad/edition-mint.js +9 -7
  54. package/dist/components/launchpad/edition-mint.js.map +1 -1
  55. package/dist/components/launchpad/pop-create.cjs +5 -6
  56. package/dist/components/launchpad/pop-create.cjs.map +1 -1
  57. package/dist/components/launchpad/pop-create.js +5 -6
  58. package/dist/components/launchpad/pop-create.js.map +1 -1
  59. package/dist/components/launchpad/remix-mint.cjs +9 -7
  60. package/dist/components/launchpad/remix-mint.cjs.map +1 -1
  61. package/dist/components/launchpad/remix-mint.js +9 -7
  62. package/dist/components/launchpad/remix-mint.js.map +1 -1
  63. package/dist/components/launchpad/single-edition-mint.cjs +9 -7
  64. package/dist/components/launchpad/single-edition-mint.cjs.map +1 -1
  65. package/dist/components/launchpad/single-edition-mint.js +9 -7
  66. package/dist/components/launchpad/single-edition-mint.js.map +1 -1
  67. package/dist/components/launchpad/sponsorship-create.cjs +5 -6
  68. package/dist/components/launchpad/sponsorship-create.cjs.map +1 -1
  69. package/dist/components/launchpad/sponsorship-create.js +5 -6
  70. package/dist/components/launchpad/sponsorship-create.js.map +1 -1
  71. package/dist/components/launchpad/tier-mint-form.cjs +5 -6
  72. package/dist/components/launchpad/tier-mint-form.cjs.map +1 -1
  73. package/dist/components/launchpad/tier-mint-form.js +5 -6
  74. package/dist/components/launchpad/tier-mint-form.js.map +1 -1
  75. package/dist/components/launchpad/tier-mint-presets.cjs +2 -2
  76. package/dist/components/launchpad/tier-mint-presets.cjs.map +1 -1
  77. package/dist/components/launchpad/tier-mint-presets.d.cts +2 -1
  78. package/dist/components/launchpad/tier-mint-presets.d.ts +2 -1
  79. package/dist/components/launchpad/tier-mint-presets.js +2 -2
  80. package/dist/components/launchpad/tier-mint-presets.js.map +1 -1
  81. package/dist/components/marketplace-dialog-primitives.cjs +1 -31
  82. package/dist/components/marketplace-dialog-primitives.cjs.map +1 -1
  83. package/dist/components/marketplace-dialog-primitives.d.cts +1 -12
  84. package/dist/components/marketplace-dialog-primitives.d.ts +1 -12
  85. package/dist/components/marketplace-dialog-primitives.js +2 -31
  86. package/dist/components/marketplace-dialog-primitives.js.map +1 -1
  87. package/dist/components/media-wallet/media-wallet-activity.cjs +5 -1
  88. package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
  89. package/dist/components/media-wallet/media-wallet-activity.js +5 -1
  90. package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
  91. package/dist/components/media-wallet/media-wallet-home.cjs +3 -2
  92. package/dist/components/media-wallet/media-wallet-home.cjs.map +1 -1
  93. package/dist/components/media-wallet/media-wallet-home.js +3 -2
  94. package/dist/components/media-wallet/media-wallet-home.js.map +1 -1
  95. package/dist/components/media-wallet/media-wallet-send.cjs +5 -2
  96. package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
  97. package/dist/components/media-wallet/media-wallet-send.js +5 -2
  98. package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
  99. package/dist/components/media-wallet/success-dialog.cjs +5 -11
  100. package/dist/components/media-wallet/success-dialog.cjs.map +1 -1
  101. package/dist/components/media-wallet/success-dialog.js +5 -11
  102. package/dist/components/media-wallet/success-dialog.js.map +1 -1
  103. package/dist/components/pop-claim-button.cjs +7 -6
  104. package/dist/components/pop-claim-button.cjs.map +1 -1
  105. package/dist/components/pop-claim-button.js +7 -6
  106. package/dist/components/pop-claim-button.js.map +1 -1
  107. package/dist/components/pop-manage-page.cjs +5 -4
  108. package/dist/components/pop-manage-page.cjs.map +1 -1
  109. package/dist/components/pop-manage-page.js +5 -4
  110. package/dist/components/pop-manage-page.js.map +1 -1
  111. package/dist/components/portfolio-sponsorships.cjs +15 -8
  112. package/dist/components/portfolio-sponsorships.cjs.map +1 -1
  113. package/dist/components/portfolio-sponsorships.js +15 -8
  114. package/dist/components/portfolio-sponsorships.js.map +1 -1
  115. package/dist/components/service-collections-page.cjs +2 -2
  116. package/dist/components/service-collections-page.cjs.map +1 -1
  117. package/dist/components/service-collections-page.d.cts +2 -2
  118. package/dist/components/service-collections-page.d.ts +2 -2
  119. package/dist/components/service-collections-page.js +2 -2
  120. package/dist/components/service-collections-page.js.map +1 -1
  121. package/dist/components/sheet.d.cts +1 -1
  122. package/dist/components/sheet.d.ts +1 -1
  123. package/dist/components/sponsorship-offer-page.cjs +9 -8
  124. package/dist/components/sponsorship-offer-page.cjs.map +1 -1
  125. package/dist/components/sponsorship-offer-page.js +9 -8
  126. package/dist/components/sponsorship-offer-page.js.map +1 -1
  127. package/dist/components/transaction-success.cjs +60 -0
  128. package/dist/components/transaction-success.cjs.map +1 -0
  129. package/dist/components/transaction-success.d.cts +20 -0
  130. package/dist/components/transaction-success.d.ts +20 -0
  131. package/dist/components/transaction-success.js +26 -0
  132. package/dist/components/transaction-success.js.map +1 -0
  133. package/dist/components/transfer-collection-ownership.cjs +6 -8
  134. package/dist/components/transfer-collection-ownership.cjs.map +1 -1
  135. package/dist/components/transfer-collection-ownership.js +6 -8
  136. package/dist/components/transfer-collection-ownership.js.map +1 -1
  137. package/dist/index.cjs +9 -8
  138. package/dist/index.cjs.map +1 -1
  139. package/dist/index.d.cts +4 -3
  140. package/dist/index.d.ts +4 -3
  141. package/dist/index.js +6 -6
  142. package/dist/index.js.map +1 -1
  143. package/dist/utils/empty-messages.cjs +62 -0
  144. package/dist/utils/empty-messages.cjs.map +1 -0
  145. package/dist/utils/empty-messages.d.cts +40 -0
  146. package/dist/utils/empty-messages.d.ts +40 -0
  147. package/dist/utils/empty-messages.js +38 -0
  148. package/dist/utils/empty-messages.js.map +1 -0
  149. package/dist/utils/success-messages.cjs +106 -0
  150. package/dist/utils/success-messages.cjs.map +1 -0
  151. package/dist/utils/success-messages.d.cts +58 -0
  152. package/dist/utils/success-messages.d.ts +58 -0
  153. package/dist/utils/success-messages.js +82 -0
  154. package/dist/utils/success-messages.js.map +1 -0
  155. package/package.json +3 -3
  156. package/dist/components/creation-success.cjs +0 -64
  157. package/dist/components/creation-success.cjs.map +0 -1
  158. package/dist/components/creation-success.d.cts +0 -20
  159. package/dist/components/creation-success.d.ts +0 -20
  160. package/dist/components/creation-success.js +0 -30
  161. package/dist/components/creation-success.js.map +0 -1
  162. package/dist/components/transaction-done.cjs +0 -46
  163. package/dist/components/transaction-done.cjs.map +0 -1
  164. package/dist/components/transaction-done.d.cts +0 -18
  165. package/dist/components/transaction-done.d.ts +0 -18
  166. package/dist/components/transaction-done.js +0 -22
  167. package/dist/components/transaction-done.js.map +0 -1
@@ -43,6 +43,7 @@ var import_lucide_react = require("lucide-react");
43
43
  var import_activity = require("../data/activity.js");
44
44
  var import_activity_row = require("./activity-row.js");
45
45
  var import_cn = require("../utils/cn.js");
46
+ var import_empty_messages = require("../utils/empty-messages.js");
46
47
  async function fetchAnnouncements() {
47
48
  const res = await fetch("/api/announcements");
48
49
  if (!res.ok) return [];
@@ -175,7 +176,10 @@ function ActivitiesFeed() {
175
176
  ] })
176
177
  ] }, i)) }) : allActivities.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "py-20 flex flex-col items-center gap-3 text-center", children: [
177
178
  /* @__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" }) }),
178
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-muted-foreground", children: typeFilter ? `No ${typeFilter} events yet.` : "No activity yet." })
179
+ typeFilter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-muted-foreground", children: `No ${typeFilter} events yet.` }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "font-medium", children: import_empty_messages.emptyMessages.activity.title }),
181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground", children: import_empty_messages.emptyMessages.activity.description })
182
+ ] })
179
183
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
180
184
  /* @__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) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
185
  import_activity_row.ActivityRow,
@@ -1 +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 type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\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-2xs 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 function ActivitiesFeed() {\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({\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 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 <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\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"]}
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 type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\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\";\nimport { emptyMessages } from \"../utils/empty-messages.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-2xs 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 function ActivitiesFeed() {\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({\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 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 {typeFilter ? (\n <p className=\"text-muted-foreground\">{`No ${typeFilter} events yet.`}</p>\n ) : (\n <div>\n <p className=\"font-medium\">{emptyMessages.activity.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.activity.description}</p>\n </div>\n )}\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 <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\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"]}
@@ -10,6 +10,7 @@ import { Zap, Megaphone, ArrowRight, Pin } from "lucide-react";
10
10
  import { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from "../data/activity.js";
11
11
  import { ActivityRow } from "./activity-row.js";
12
12
  import { cn } from "../utils/cn.js";
13
+ import { emptyMessages } from "../utils/empty-messages.js";
13
14
  async function fetchAnnouncements() {
14
15
  const res = await fetch("/api/announcements");
15
16
  if (!res.ok) return [];
@@ -142,7 +143,10 @@ function ActivitiesFeed() {
142
143
  ] })
143
144
  ] }, i)) }) : allActivities.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "py-20 flex flex-col items-center gap-3 text-center", children: [
144
145
  /* @__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" }) }),
145
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: typeFilter ? `No ${typeFilter} events yet.` : "No activity yet." })
146
+ typeFilter ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: `No ${typeFilter} events yet.` }) : /* @__PURE__ */ jsxs("div", { children: [
147
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: emptyMessages.activity.title }),
148
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessages.activity.description })
149
+ ] })
146
150
  ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
147
151
  /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/50 rounded-xl border border-border overflow-hidden", children: allActivities.map((activity, i) => /* @__PURE__ */ jsx(
148
152
  ActivityRow,
@@ -1 +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 type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\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-2xs 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 function ActivitiesFeed() {\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({\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 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 <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\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":[]}
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 type { ApiActivitiesQuery, ApiActivity } from \"@medialane/sdk\";\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\";\nimport { emptyMessages } from \"../utils/empty-messages.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-2xs 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 function ActivitiesFeed() {\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({\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 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 {typeFilter ? (\n <p className=\"text-muted-foreground\">{`No ${typeFilter} events yet.`}</p>\n ) : (\n <div>\n <p className=\"font-medium\">{emptyMessages.activity.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.activity.description}</p>\n </div>\n )}\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 <ActivityRow\n key={`${activity.txHash}-${activity.type}-${activity.nftTokenId ?? i}`}\n activity={activity}\n showActor\n showExplorer\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":[]}
@@ -36,6 +36,7 @@ var import_jsx_runtime = require("react/jsx-runtime");
36
36
  var import_link = __toESM(require("./link.js"), 1);
37
37
  var import_lucide_react = require("lucide-react");
38
38
  var import_time = require("../utils/time.js");
39
+ var import_empty_messages = require("../utils/empty-messages.js");
39
40
  function SkeletonRow() {
40
41
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 px-4 py-2.5", children: [
41
42
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0" }),
@@ -79,7 +80,8 @@ function ActivityFeedShell({ title, href, hrefLabel = "Activities", lastUpdated,
79
80
  ] }),
80
81
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bento-cell overflow-hidden divide-y divide-border/40", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkeletonRow, {}, i)) : !children || Array.isArray(children) && children.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center gap-2 py-10 text-center", children: [
81
82
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Activity, { className: "h-8 w-8 text-muted-foreground/30" }),
82
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground", children: "No activity yet." })
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-medium", children: import_empty_messages.emptyMessages.activity.title }),
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground", children: import_empty_messages.emptyMessages.activity.description })
83
85
  ] }) : children })
84
86
  ] });
85
87
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/activity-feed-shell.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight, Activity, RefreshCw } from \"lucide-react\";\nimport { timeAgo } from \"../utils/time.js\";\n\nexport interface ActivityFeedShellProps {\n title: string;\n href: string;\n hrefLabel?: string;\n lastUpdated: string;\n isLoading: boolean;\n children: React.ReactNode;\n}\n\nfunction SkeletonRow() {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5\">\n <div className=\"h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0\" />\n <div className=\"h-7 w-7 rounded-md bg-muted animate-pulse shrink-0\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-3 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-20 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"space-y-1 text-right\">\n <div className=\"h-3.5 w-14 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-8 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-3 w-10 bg-muted animate-pulse rounded hidden sm:block\" />\n </div>\n );\n}\n\nexport function ActivityFeedShell({ title, href, hrefLabel = \"Activities\", lastUpdated, isLoading, children }: ActivityFeedShellProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative h-8 w-8 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center shadow-lg shadow-indigo-500/20 shrink-0\">\n <Activity className=\"h-4 w-4 text-white\" />\n <span className=\"absolute -top-1 -right-1 flex h-2.5 w-2.5\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75\" />\n <span className=\"relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500\" />\n </span>\n </div>\n <div>\n <h2 className=\"text-xl sm:text-2xl font-black leading-none\">{title}</h2>\n <p className=\"text-2xs text-muted-foreground mt-0.5 flex items-center gap-1\">\n <RefreshCw className=\"h-2.5 w-2.5\" />\n Updated {timeAgo(lastUpdated)}\n </p>\n </div>\n </div>\n <Link href={href} className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\">\n {hrefLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"bento-cell overflow-hidden divide-y divide-border/40\">\n {isLoading ? (\n Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)\n ) : !children || (Array.isArray(children) && children.length === 0) ? (\n <div className=\"flex flex-col items-center gap-2 py-10 text-center\">\n <Activity className=\"h-8 w-8 text-muted-foreground/30\" />\n <p className=\"text-sm text-muted-foreground\">No activity yet.</p>\n </div>\n ) : (\n children\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBM;AAhBN,kBAAiB;AACjB,0BAAgD;AAChD,kBAAwB;AAWxB,SAAS,cAAc;AACrB,SACE,6CAAC,SAAI,WAAU,uCACb;AAAA,gDAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,4CAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,6CAAC,SAAI,WAAU,sBACb;AAAA,kDAAC,SAAI,WAAU,2CAA0C;AAAA,MACzD,4CAAC,SAAI,WAAU,6CAA4C;AAAA,OAC7D;AAAA,IACA,6CAAC,SAAI,WAAU,wBACb;AAAA,kDAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,4CAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,IACA,4CAAC,SAAI,WAAU,2DAA0D;AAAA,KAC3E;AAEJ;AAEO,SAAS,kBAAkB,EAAE,OAAO,MAAM,YAAY,cAAc,aAAa,WAAW,SAAS,GAA2B;AACrI,SACE,6CAAC,aAAQ,WAAU,aACjB;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,SAAI,WAAU,6BACb;AAAA,qDAAC,SAAI,WAAU,sJACb;AAAA,sDAAC,gCAAS,WAAU,sBAAqB;AAAA,UACzC,6CAAC,UAAK,WAAU,6CACd;AAAA,wDAAC,UAAK,WAAU,0FAAyF;AAAA,YACzG,4CAAC,UAAK,WAAU,gEAA+D;AAAA,aACjF;AAAA,WACF;AAAA,QACA,6CAAC,SACC;AAAA,sDAAC,QAAG,WAAU,+CAA+C,iBAAM;AAAA,UACnE,6CAAC,OAAE,WAAU,iEACX;AAAA,wDAAC,iCAAU,WAAU,eAAc;AAAA,YAAE;AAAA,gBAC5B,qBAAQ,WAAW;AAAA,aAC9B;AAAA,WACF;AAAA,SACF;AAAA,MACA,6CAAC,YAAAA,SAAA,EAAK,MAAY,WAAU,+IACzB;AAAA;AAAA,QAAU;AAAA,QAAC,4CAAC,kCAAW,WAAU,eAAc;AAAA,SAClD;AAAA,OACF;AAAA,IAEA,4CAAC,SAAI,WAAU,wDACZ,sBACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,4CAAC,iBAAiB,CAAG,CAAE,IAC7D,CAAC,YAAa,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,IAC/D,6CAAC,SAAI,WAAU,sDACb;AAAA,kDAAC,gCAAS,WAAU,oCAAmC;AAAA,MACvD,4CAAC,OAAE,WAAU,iCAAgC,8BAAgB;AAAA,OAC/D,IAEA,UAEJ;AAAA,KACF;AAEJ;","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/activity-feed-shell.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight, Activity, RefreshCw } from \"lucide-react\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nexport interface ActivityFeedShellProps {\n title: string;\n href: string;\n hrefLabel?: string;\n lastUpdated: string;\n isLoading: boolean;\n children: React.ReactNode;\n}\n\nfunction SkeletonRow() {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5\">\n <div className=\"h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0\" />\n <div className=\"h-7 w-7 rounded-md bg-muted animate-pulse shrink-0\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-3 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-20 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"space-y-1 text-right\">\n <div className=\"h-3.5 w-14 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-8 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-3 w-10 bg-muted animate-pulse rounded hidden sm:block\" />\n </div>\n );\n}\n\nexport function ActivityFeedShell({ title, href, hrefLabel = \"Activities\", lastUpdated, isLoading, children }: ActivityFeedShellProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative h-8 w-8 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center shadow-lg shadow-indigo-500/20 shrink-0\">\n <Activity className=\"h-4 w-4 text-white\" />\n <span className=\"absolute -top-1 -right-1 flex h-2.5 w-2.5\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75\" />\n <span className=\"relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500\" />\n </span>\n </div>\n <div>\n <h2 className=\"text-xl sm:text-2xl font-black leading-none\">{title}</h2>\n <p className=\"text-2xs text-muted-foreground mt-0.5 flex items-center gap-1\">\n <RefreshCw className=\"h-2.5 w-2.5\" />\n Updated {timeAgo(lastUpdated)}\n </p>\n </div>\n </div>\n <Link href={href} className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\">\n {hrefLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"bento-cell overflow-hidden divide-y divide-border/40\">\n {isLoading ? (\n Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)\n ) : !children || (Array.isArray(children) && children.length === 0) ? (\n <div className=\"flex flex-col items-center gap-2 py-10 text-center\">\n <Activity className=\"h-8 w-8 text-muted-foreground/30\" />\n <p className=\"text-sm font-medium\">{emptyMessages.activity.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.activity.description}</p>\n </div>\n ) : (\n children\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBM;AAjBN,kBAAiB;AACjB,0BAAgD;AAChD,kBAAwB;AACxB,4BAA8B;AAW9B,SAAS,cAAc;AACrB,SACE,6CAAC,SAAI,WAAU,uCACb;AAAA,gDAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,4CAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,6CAAC,SAAI,WAAU,sBACb;AAAA,kDAAC,SAAI,WAAU,2CAA0C;AAAA,MACzD,4CAAC,SAAI,WAAU,6CAA4C;AAAA,OAC7D;AAAA,IACA,6CAAC,SAAI,WAAU,wBACb;AAAA,kDAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,4CAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,IACA,4CAAC,SAAI,WAAU,2DAA0D;AAAA,KAC3E;AAEJ;AAEO,SAAS,kBAAkB,EAAE,OAAO,MAAM,YAAY,cAAc,aAAa,WAAW,SAAS,GAA2B;AACrI,SACE,6CAAC,aAAQ,WAAU,aACjB;AAAA,iDAAC,SAAI,WAAU,qCACb;AAAA,mDAAC,SAAI,WAAU,6BACb;AAAA,qDAAC,SAAI,WAAU,sJACb;AAAA,sDAAC,gCAAS,WAAU,sBAAqB;AAAA,UACzC,6CAAC,UAAK,WAAU,6CACd;AAAA,wDAAC,UAAK,WAAU,0FAAyF;AAAA,YACzG,4CAAC,UAAK,WAAU,gEAA+D;AAAA,aACjF;AAAA,WACF;AAAA,QACA,6CAAC,SACC;AAAA,sDAAC,QAAG,WAAU,+CAA+C,iBAAM;AAAA,UACnE,6CAAC,OAAE,WAAU,iEACX;AAAA,wDAAC,iCAAU,WAAU,eAAc;AAAA,YAAE;AAAA,gBAC5B,qBAAQ,WAAW;AAAA,aAC9B;AAAA,WACF;AAAA,SACF;AAAA,MACA,6CAAC,YAAAA,SAAA,EAAK,MAAY,WAAU,+IACzB;AAAA;AAAA,QAAU;AAAA,QAAC,4CAAC,kCAAW,WAAU,eAAc;AAAA,SAClD;AAAA,OACF;AAAA,IAEA,4CAAC,SAAI,WAAU,wDACZ,sBACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,4CAAC,iBAAiB,CAAG,CAAE,IAC7D,CAAC,YAAa,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,IAC/D,6CAAC,SAAI,WAAU,sDACb;AAAA,kDAAC,gCAAS,WAAU,oCAAmC;AAAA,MACvD,4CAAC,OAAE,WAAU,uBAAuB,8CAAc,SAAS,OAAM;AAAA,MACjE,4CAAC,OAAE,WAAU,iCAAiC,8CAAc,SAAS,aAAY;AAAA,OACnF,IAEA,UAEJ;AAAA,KACF;AAEJ;","names":["Link"]}
@@ -3,6 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Link from "./link.js";
4
4
  import { ArrowRight, Activity, RefreshCw } from "lucide-react";
5
5
  import { timeAgo } from "../utils/time.js";
6
+ import { emptyMessages } from "../utils/empty-messages.js";
6
7
  function SkeletonRow() {
7
8
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-2.5", children: [
8
9
  /* @__PURE__ */ jsx("div", { className: "h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0" }),
@@ -46,7 +47,8 @@ function ActivityFeedShell({ title, href, hrefLabel = "Activities", lastUpdated,
46
47
  ] }),
47
48
  /* @__PURE__ */ jsx("div", { className: "bento-cell overflow-hidden divide-y divide-border/40", children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, i)) : !children || Array.isArray(children) && children.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-10 text-center", children: [
48
49
  /* @__PURE__ */ jsx(Activity, { className: "h-8 w-8 text-muted-foreground/30" }),
49
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No activity yet." })
50
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: emptyMessages.activity.title }),
51
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessages.activity.description })
50
52
  ] }) : children })
51
53
  ] });
52
54
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/activity-feed-shell.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight, Activity, RefreshCw } from \"lucide-react\";\nimport { timeAgo } from \"../utils/time.js\";\n\nexport interface ActivityFeedShellProps {\n title: string;\n href: string;\n hrefLabel?: string;\n lastUpdated: string;\n isLoading: boolean;\n children: React.ReactNode;\n}\n\nfunction SkeletonRow() {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5\">\n <div className=\"h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0\" />\n <div className=\"h-7 w-7 rounded-md bg-muted animate-pulse shrink-0\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-3 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-20 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"space-y-1 text-right\">\n <div className=\"h-3.5 w-14 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-8 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-3 w-10 bg-muted animate-pulse rounded hidden sm:block\" />\n </div>\n );\n}\n\nexport function ActivityFeedShell({ title, href, hrefLabel = \"Activities\", lastUpdated, isLoading, children }: ActivityFeedShellProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative h-8 w-8 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center shadow-lg shadow-indigo-500/20 shrink-0\">\n <Activity className=\"h-4 w-4 text-white\" />\n <span className=\"absolute -top-1 -right-1 flex h-2.5 w-2.5\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75\" />\n <span className=\"relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500\" />\n </span>\n </div>\n <div>\n <h2 className=\"text-xl sm:text-2xl font-black leading-none\">{title}</h2>\n <p className=\"text-2xs text-muted-foreground mt-0.5 flex items-center gap-1\">\n <RefreshCw className=\"h-2.5 w-2.5\" />\n Updated {timeAgo(lastUpdated)}\n </p>\n </div>\n </div>\n <Link href={href} className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\">\n {hrefLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"bento-cell overflow-hidden divide-y divide-border/40\">\n {isLoading ? (\n Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)\n ) : !children || (Array.isArray(children) && children.length === 0) ? (\n <div className=\"flex flex-col items-center gap-2 py-10 text-center\">\n <Activity className=\"h-8 w-8 text-muted-foreground/30\" />\n <p className=\"text-sm text-muted-foreground\">No activity yet.</p>\n </div>\n ) : (\n children\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";AAkBM,cAEA,YAFA;AAhBN,OAAO,UAAU;AACjB,SAAS,YAAY,UAAU,iBAAiB;AAChD,SAAS,eAAe;AAWxB,SAAS,cAAc;AACrB,SACE,qBAAC,SAAI,WAAU,uCACb;AAAA,wBAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,oBAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,qBAAC,SAAI,WAAU,sBACb;AAAA,0BAAC,SAAI,WAAU,2CAA0C;AAAA,MACzD,oBAAC,SAAI,WAAU,6CAA4C;AAAA,OAC7D;AAAA,IACA,qBAAC,SAAI,WAAU,wBACb;AAAA,0BAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,oBAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,IACA,oBAAC,SAAI,WAAU,2DAA0D;AAAA,KAC3E;AAEJ;AAEO,SAAS,kBAAkB,EAAE,OAAO,MAAM,YAAY,cAAc,aAAa,WAAW,SAAS,GAA2B;AACrI,SACE,qBAAC,aAAQ,WAAU,aACjB;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SAAI,WAAU,6BACb;AAAA,6BAAC,SAAI,WAAU,sJACb;AAAA,8BAAC,YAAS,WAAU,sBAAqB;AAAA,UACzC,qBAAC,UAAK,WAAU,6CACd;AAAA,gCAAC,UAAK,WAAU,0FAAyF;AAAA,YACzG,oBAAC,UAAK,WAAU,gEAA+D;AAAA,aACjF;AAAA,WACF;AAAA,QACA,qBAAC,SACC;AAAA,8BAAC,QAAG,WAAU,+CAA+C,iBAAM;AAAA,UACnE,qBAAC,OAAE,WAAU,iEACX;AAAA,gCAAC,aAAU,WAAU,eAAc;AAAA,YAAE;AAAA,YAC5B,QAAQ,WAAW;AAAA,aAC9B;AAAA,WACF;AAAA,SACF;AAAA,MACA,qBAAC,QAAK,MAAY,WAAU,+IACzB;AAAA;AAAA,QAAU;AAAA,QAAC,oBAAC,cAAW,WAAU,eAAc;AAAA,SAClD;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,wDACZ,sBACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,iBAAiB,CAAG,CAAE,IAC7D,CAAC,YAAa,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,IAC/D,qBAAC,SAAI,WAAU,sDACb;AAAA,0BAAC,YAAS,WAAU,oCAAmC;AAAA,MACvD,oBAAC,OAAE,WAAU,iCAAgC,8BAAgB;AAAA,OAC/D,IAEA,UAEJ;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/activity-feed-shell.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { ArrowRight, Activity, RefreshCw } from \"lucide-react\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nexport interface ActivityFeedShellProps {\n title: string;\n href: string;\n hrefLabel?: string;\n lastUpdated: string;\n isLoading: boolean;\n children: React.ReactNode;\n}\n\nfunction SkeletonRow() {\n return (\n <div className=\"flex items-center gap-3 px-4 py-2.5\">\n <div className=\"h-7 w-7 rounded-lg bg-muted animate-pulse shrink-0\" />\n <div className=\"h-7 w-7 rounded-md bg-muted animate-pulse shrink-0\" />\n <div className=\"flex-1 space-y-1.5\">\n <div className=\"h-3 w-32 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-20 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"space-y-1 text-right\">\n <div className=\"h-3.5 w-14 bg-muted animate-pulse rounded\" />\n <div className=\"h-2.5 w-8 bg-muted animate-pulse rounded\" />\n </div>\n <div className=\"h-3 w-10 bg-muted animate-pulse rounded hidden sm:block\" />\n </div>\n );\n}\n\nexport function ActivityFeedShell({ title, href, hrefLabel = \"Activities\", lastUpdated, isLoading, children }: ActivityFeedShellProps) {\n return (\n <section className=\"space-y-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2.5\">\n <div className=\"relative h-8 w-8 rounded-xl bg-gradient-to-br from-indigo-500 to-blue-600 flex items-center justify-center shadow-lg shadow-indigo-500/20 shrink-0\">\n <Activity className=\"h-4 w-4 text-white\" />\n <span className=\"absolute -top-1 -right-1 flex h-2.5 w-2.5\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75\" />\n <span className=\"relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500\" />\n </span>\n </div>\n <div>\n <h2 className=\"text-xl sm:text-2xl font-black leading-none\">{title}</h2>\n <p className=\"text-2xs text-muted-foreground mt-0.5 flex items-center gap-1\">\n <RefreshCw className=\"h-2.5 w-2.5\" />\n Updated {timeAgo(lastUpdated)}\n </p>\n </div>\n </div>\n <Link href={href} className=\"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md hover:bg-accent transition-colors\">\n {hrefLabel} <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n <div className=\"bento-cell overflow-hidden divide-y divide-border/40\">\n {isLoading ? (\n Array.from({ length: 6 }).map((_, i) => <SkeletonRow key={i} />)\n ) : !children || (Array.isArray(children) && children.length === 0) ? (\n <div className=\"flex flex-col items-center gap-2 py-10 text-center\">\n <Activity className=\"h-8 w-8 text-muted-foreground/30\" />\n <p className=\"text-sm font-medium\">{emptyMessages.activity.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.activity.description}</p>\n </div>\n ) : (\n children\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";AAmBM,cAEA,YAFA;AAjBN,OAAO,UAAU;AACjB,SAAS,YAAY,UAAU,iBAAiB;AAChD,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAW9B,SAAS,cAAc;AACrB,SACE,qBAAC,SAAI,WAAU,uCACb;AAAA,wBAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,oBAAC,SAAI,WAAU,sDAAqD;AAAA,IACpE,qBAAC,SAAI,WAAU,sBACb;AAAA,0BAAC,SAAI,WAAU,2CAA0C;AAAA,MACzD,oBAAC,SAAI,WAAU,6CAA4C;AAAA,OAC7D;AAAA,IACA,qBAAC,SAAI,WAAU,wBACb;AAAA,0BAAC,SAAI,WAAU,6CAA4C;AAAA,MAC3D,oBAAC,SAAI,WAAU,4CAA2C;AAAA,OAC5D;AAAA,IACA,oBAAC,SAAI,WAAU,2DAA0D;AAAA,KAC3E;AAEJ;AAEO,SAAS,kBAAkB,EAAE,OAAO,MAAM,YAAY,cAAc,aAAa,WAAW,SAAS,GAA2B;AACrI,SACE,qBAAC,aAAQ,WAAU,aACjB;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,SAAI,WAAU,6BACb;AAAA,6BAAC,SAAI,WAAU,sJACb;AAAA,8BAAC,YAAS,WAAU,sBAAqB;AAAA,UACzC,qBAAC,UAAK,WAAU,6CACd;AAAA,gCAAC,UAAK,WAAU,0FAAyF;AAAA,YACzG,oBAAC,UAAK,WAAU,gEAA+D;AAAA,aACjF;AAAA,WACF;AAAA,QACA,qBAAC,SACC;AAAA,8BAAC,QAAG,WAAU,+CAA+C,iBAAM;AAAA,UACnE,qBAAC,OAAE,WAAU,iEACX;AAAA,gCAAC,aAAU,WAAU,eAAc;AAAA,YAAE;AAAA,YAC5B,QAAQ,WAAW;AAAA,aAC9B;AAAA,WACF;AAAA,SACF;AAAA,MACA,qBAAC,QAAK,MAAY,WAAU,+IACzB;AAAA;AAAA,QAAU;AAAA,QAAC,oBAAC,cAAW,WAAU,eAAc;AAAA,SAClD;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,wDACZ,sBACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,oBAAC,iBAAiB,CAAG,CAAE,IAC7D,CAAC,YAAa,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,IAC/D,qBAAC,SAAI,WAAU,sDACb;AAAA,0BAAC,YAAS,WAAU,oCAAmC;AAAA,MACvD,oBAAC,OAAE,WAAU,uBAAuB,wBAAc,SAAS,OAAM;AAAA,MACjE,oBAAC,OAAE,WAAU,iCAAiC,wBAAc,SAAS,aAAY;AAAA,OACnF,IAEA,UAEJ;AAAA,KACF;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?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
6
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
7
7
  size?: "default" | "icon" | "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?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
6
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
7
7
  size?: "default" | "icon" | "sm" | "lg" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -30,6 +30,7 @@ var import_coin_row = require("./coin-row.js");
30
30
  var import_stat_tile = require("./stat-tile.js");
31
31
  var import_coin_order = require("../data/coin-order.js");
32
32
  var import_coins = require("../data/coins.js");
33
+ var import_empty_messages = require("../utils/empty-messages.js");
33
34
  const SORT_OPTIONS = [
34
35
  { label: "Recently launched", value: "recent" },
35
36
  { label: "Name", value: "name" }
@@ -117,7 +118,10 @@ function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = tr
117
118
  }
118
119
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-right", children: "Price" })
119
120
  ] }),
120
- isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_row.CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "py-16 text-center text-sm text-muted-foreground", children: query.trim() ? `No coins match "${query.trim()}".` : "No coins yet." }) : items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
121
+ isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_coin_row.CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "py-16 text-center", children: query.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground", children: `No coins match "${query.trim()}".` }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-medium", children: import_empty_messages.emptyMessages.coins.title }),
123
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-muted-foreground", children: import_empty_messages.emptyMessages.coins.description })
124
+ ] }) }) : items.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
121
125
  import_coin_row.CoinRow,
122
126
  {
123
127
  collection: c,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { orderCoins, type CoinPriceSort } from \"../data/coin-order.js\";\nimport { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport type UsePriceMap = () => { prices: Record<string, number | null>; isLoading: boolean };\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n usePriceMap?: UsePriceMap;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst noPriceMap: UsePriceMap = () => ({ prices: {}, isLoading: false });\n\nexport function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [priceSort, setPriceSort] = useState<CoinPriceSort | undefined>(undefined);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const { prices } = (usePriceMap ?? noPriceMap)();\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n const matched = q\n ? collections.filter((c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q))\n : collections;\n return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;\n }, [collections, query, usePriceMap, prices, priceSort]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const { statItems, pillFilters } = useMemo(() => {\n if (!counts) return { statItems: [], pillFilters: [] as CoinFilter[] };\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);\n return {\n statItems: [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })),\n ],\n pillFilters: [\"all\", ...kinds] as CoinFilter[],\n };\n }, [counts]);\n\n const activeIndex = pillFilters.indexOf(filter);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins &amp; memecoins</h1>\n <StatPillRow\n items={statItems}\n onSelect={(index) => setFilter(pillFilters[index])}\n activeIndex={activeIndex}\n />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n aria-label=\"Sort coins\"\n className=\"shrink-0 rounded-lg border border-border bg-background px-2.5 py-2 text-xs font-medium text-foreground outline-none focus:border-primary/50\"\n >\n {SORT_OPTIONS.map(({ label, value }) => (\n <option key={value} value={value}>{label}</option>\n ))}\n </select>\n </div>\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n {usePriceMap ? (\n <button\n type=\"button\"\n onClick={() => setPriceSort(priceSort === undefined ? \"desc\" : priceSort === \"desc\" ? \"asc\" : undefined)}\n className={cn(\"text-right uppercase tracking-wide\", priceSort ? \"text-foreground\" : \"text-muted-foreground\")}\n >\n Price{priceSort === \"desc\" ? \" ↓\" : priceSort === \"asc\" ? \" ↑\" : \"\"}\n </button>\n ) : (\n <span className=\"text-right\">Price</span>\n )}\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </p>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { orderCoins, type CoinPriceSort } from \"../data/coin-order.js\";\nimport { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport type UsePriceMap = () => { prices: Record<string, number | null>; isLoading: boolean };\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n usePriceMap?: UsePriceMap;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst noPriceMap: UsePriceMap = () => ({ prices: {}, isLoading: false });\n\nexport function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [priceSort, setPriceSort] = useState<CoinPriceSort | undefined>(undefined);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const { prices } = (usePriceMap ?? noPriceMap)();\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n const matched = q\n ? collections.filter((c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q))\n : collections;\n return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;\n }, [collections, query, usePriceMap, prices, priceSort]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const { statItems, pillFilters } = useMemo(() => {\n if (!counts) return { statItems: [], pillFilters: [] as CoinFilter[] };\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);\n return {\n statItems: [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })),\n ],\n pillFilters: [\"all\", ...kinds] as CoinFilter[],\n };\n }, [counts]);\n\n const activeIndex = pillFilters.indexOf(filter);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins &amp; memecoins</h1>\n <StatPillRow\n items={statItems}\n onSelect={(index) => setFilter(pillFilters[index])}\n activeIndex={activeIndex}\n />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n aria-label=\"Sort coins\"\n className=\"shrink-0 rounded-lg border border-border bg-background px-2.5 py-2 text-xs font-medium text-foreground outline-none focus:border-primary/50\"\n >\n {SORT_OPTIONS.map(({ label, value }) => (\n <option key={value} value={value}>{label}</option>\n ))}\n </select>\n </div>\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n {usePriceMap ? (\n <button\n type=\"button\"\n onClick={() => setPriceSort(priceSort === undefined ? \"desc\" : priceSort === \"desc\" ? \"asc\" : undefined)}\n className={cn(\"text-right uppercase tracking-wide\", priceSort ? \"text-foreground\" : \"text-muted-foreground\")}\n >\n Price{priceSort === \"desc\" ? \" ↓\" : priceSort === \"asc\" ? \" ↑\" : \"\"}\n </button>\n ) : (\n <span className=\"text-right\">Price</span>\n )}\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <div className=\"py-16 text-center\">\n {query.trim() ? (\n <p className=\"text-sm text-muted-foreground\">{`No coins match \"${query.trim()}\".`}</p>\n ) : (\n <>\n <p className=\"text-sm font-medium\">{emptyMessages.coins.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.coins.description}</p>\n </>\n )}\n </div>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState, useMemo } from "react";
4
4
  import { Search } from "lucide-react";
5
5
  import { cn } from "../utils/cn.js";
@@ -7,6 +7,7 @@ import { CoinRow, CoinRowSkeleton, COIN_GRID } from "./coin-row.js";
7
7
  import { StatPillRow } from "./stat-tile.js";
8
8
  import { orderCoins } from "../data/coin-order.js";
9
9
  import { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS } from "../data/coins.js";
10
+ import { emptyMessages } from "../utils/empty-messages.js";
10
11
  const SORT_OPTIONS = [
11
12
  { label: "Recently launched", value: "recent" },
12
13
  { label: "Name", value: "name" }
@@ -94,7 +95,10 @@ function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = tr
94
95
  }
95
96
  ) : /* @__PURE__ */ jsx("span", { className: "text-right", children: "Price" })
96
97
  ] }),
97
- isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-16 text-center text-sm text-muted-foreground", children: query.trim() ? `No coins match "${query.trim()}".` : "No coins yet." }) : items.map((c) => /* @__PURE__ */ jsx(
98
+ isLoading && items.length === 0 ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(CoinRowSkeleton, {}, i)) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-16 text-center", children: query.trim() ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: `No coins match "${query.trim()}".` }) : /* @__PURE__ */ jsxs(Fragment, { children: [
99
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: emptyMessages.coins.title }),
100
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessages.coins.description })
101
+ ] }) }) : items.map((c) => /* @__PURE__ */ jsx(
98
102
  CoinRow,
99
103
  {
100
104
  collection: c,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { orderCoins, type CoinPriceSort } from \"../data/coin-order.js\";\nimport { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport type UsePriceMap = () => { prices: Record<string, number | null>; isLoading: boolean };\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n usePriceMap?: UsePriceMap;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst noPriceMap: UsePriceMap = () => ({ prices: {}, isLoading: false });\n\nexport function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [priceSort, setPriceSort] = useState<CoinPriceSort | undefined>(undefined);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const { prices } = (usePriceMap ?? noPriceMap)();\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n const matched = q\n ? collections.filter((c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q))\n : collections;\n return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;\n }, [collections, query, usePriceMap, prices, priceSort]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const { statItems, pillFilters } = useMemo(() => {\n if (!counts) return { statItems: [], pillFilters: [] as CoinFilter[] };\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);\n return {\n statItems: [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })),\n ],\n pillFilters: [\"all\", ...kinds] as CoinFilter[],\n };\n }, [counts]);\n\n const activeIndex = pillFilters.indexOf(filter);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins &amp; memecoins</h1>\n <StatPillRow\n items={statItems}\n onSelect={(index) => setFilter(pillFilters[index])}\n activeIndex={activeIndex}\n />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n aria-label=\"Sort coins\"\n className=\"shrink-0 rounded-lg border border-border bg-background px-2.5 py-2 text-xs font-medium text-foreground outline-none focus:border-primary/50\"\n >\n {SORT_OPTIONS.map(({ label, value }) => (\n <option key={value} value={value}>{label}</option>\n ))}\n </select>\n </div>\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n {usePriceMap ? (\n <button\n type=\"button\"\n onClick={() => setPriceSort(priceSort === undefined ? \"desc\" : priceSort === \"desc\" ? \"asc\" : undefined)}\n className={cn(\"text-right uppercase tracking-wide\", priceSort ? \"text-foreground\" : \"text-muted-foreground\")}\n >\n Price{priceSort === \"desc\" ? \" ↓\" : priceSort === \"asc\" ? \" ↑\" : \"\"}\n </button>\n ) : (\n <span className=\"text-right\">Price</span>\n )}\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <p className=\"py-16 text-center text-sm text-muted-foreground\">\n {query.trim() ? `No coins match \"${query.trim()}\".` : \"No coins yet.\"}\n </p>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/coins-explorer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Search } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport { CoinRow, CoinRowSkeleton, COIN_GRID, type UseCoinPrice } from \"./coin-row.js\";\nimport { StatPillRow } from \"./stat-tile.js\";\nimport { orderCoins, type CoinPriceSort } from \"../data/coin-order.js\";\nimport { coinKind, coinKindLabelPlural, coinServiceIds, COIN_KINDS, type CoinCollectionLike, type CoinKind } from \"../data/coins.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nexport type CoinFilter = \"all\" | CoinKind;\nexport type CoinSort = \"recent\" | \"name\";\nexport type CoinCounts = Record<string, number>;\n\nexport type UseCoins = (opts: { filter: CoinFilter; sort: CoinSort }) => {\n collections: CoinCollectionLike[];\n isLoading: boolean;\n counts?: CoinCounts;\n};\n\nexport type UsePriceMap = () => { prices: Record<string, number | null>; isLoading: boolean };\n\nexport interface CoinsExplorerProps {\n useCoins: UseCoins;\n usePrice: UseCoinPrice;\n usePriceMap?: UsePriceMap;\n\n coinHref: (collection: CoinCollectionLike) => string;\n heading?: boolean;\n\n action?: React.ReactNode;\n}\n\nconst SORT_OPTIONS: { label: string; value: CoinSort }[] = [\n { label: \"Recently launched\", value: \"recent\" },\n { label: \"Name\", value: \"name\" },\n];\n\nconst noPriceMap: UsePriceMap = () => ({ prices: {}, isLoading: false });\n\nexport function CoinsExplorer({ useCoins, usePrice, usePriceMap, coinHref, heading = true, action }: CoinsExplorerProps) {\n const [filter, setFilter] = useState<CoinFilter>(\"all\");\n const [sort, setSort] = useState<CoinSort>(\"recent\");\n const [query, setQuery] = useState(\"\");\n const [priceSort, setPriceSort] = useState<CoinPriceSort | undefined>(undefined);\n\n const { collections, isLoading, counts } = useCoins({ filter, sort });\n const { prices } = (usePriceMap ?? noPriceMap)();\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n const matched = q\n ? collections.filter((c) => (c.name ?? \"\").toLowerCase().includes(q) || (c.symbol ?? \"\").toLowerCase().includes(q))\n : collections;\n return usePriceMap ? orderCoins(matched, prices, priceSort) : matched;\n }, [collections, query, usePriceMap, prices, priceSort]);\n\n const showKind = useMemo(() => new Set(items.map((c) => coinKind(c.service))).size > 1, [items]);\n\n const { statItems, pillFilters } = useMemo(() => {\n if (!counts) return { statItems: [], pillFilters: [] as CoinFilter[] };\n const forKind = (kind: CoinKind) =>\n coinServiceIds(kind).reduce((sum, id) => sum + (counts[id] ?? 0), 0);\n const total = Object.values(counts).reduce((a, b) => a + b, 0);\n const kinds = COIN_KINDS.filter((kind) => forKind(kind) > 0);\n return {\n statItems: [\n { label: total === 1 ? \"Coin\" : \"Coins\", value: total },\n ...kinds.map((kind) => ({ label: coinKindLabelPlural(kind), value: forKind(kind) })),\n ],\n pillFilters: [\"all\", ...kinds] as CoinFilter[],\n };\n }, [counts]);\n\n const activeIndex = pillFilters.indexOf(filter);\n\n return (\n <div className=\"space-y-5\">\n {heading && (\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold\">Creator coins &amp; memecoins</h1>\n <StatPillRow\n items={statItems}\n onSelect={(index) => setFilter(pillFilters[index])}\n activeIndex={activeIndex}\n />\n </div>\n {action}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search coins by name or symbol…\"\n className=\"w-full rounded-lg border border-border bg-background py-2 pl-9 pr-3 text-sm outline-none focus:border-primary/50\"\n />\n </div>\n <select\n value={sort}\n onChange={(e) => setSort(e.target.value as CoinSort)}\n aria-label=\"Sort coins\"\n className=\"shrink-0 rounded-lg border border-border bg-background px-2.5 py-2 text-xs font-medium text-foreground outline-none focus:border-primary/50\"\n >\n {SORT_OPTIONS.map(({ label, value }) => (\n <option key={value} value={value}>{label}</option>\n ))}\n </select>\n </div>\n\n <div>\n <div className={cn(COIN_GRID, \"border-b border-border px-2 pb-2 text-2xs font-medium uppercase tracking-wide text-muted-foreground\")}>\n <span>Token</span>\n {usePriceMap ? (\n <button\n type=\"button\"\n onClick={() => setPriceSort(priceSort === undefined ? \"desc\" : priceSort === \"desc\" ? \"asc\" : undefined)}\n className={cn(\"text-right uppercase tracking-wide\", priceSort ? \"text-foreground\" : \"text-muted-foreground\")}\n >\n Price{priceSort === \"desc\" ? \" ↓\" : priceSort === \"asc\" ? \" ↑\" : \"\"}\n </button>\n ) : (\n <span className=\"text-right\">Price</span>\n )}\n </div>\n\n {isLoading && items.length === 0 ? (\n Array.from({ length: 6 }).map((_, i) => <CoinRowSkeleton key={i} />)\n ) : items.length === 0 ? (\n <div className=\"py-16 text-center\">\n {query.trim() ? (\n <p className=\"text-sm text-muted-foreground\">{`No coins match \"${query.trim()}\".`}</p>\n ) : (\n <>\n <p className=\"text-sm font-medium\">{emptyMessages.coins.title}</p>\n <p className=\"text-sm text-muted-foreground\">{emptyMessages.coins.description}</p>\n </>\n )}\n </div>\n ) : (\n items.map((c) => (\n <CoinRow\n key={`${c.chain}-${c.contractAddress}`}\n collection={c}\n usePrice={usePrice}\n href={coinHref(c)}\n showKind={showKind}\n />\n ))\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -44,11 +44,12 @@ var import_reward_earned = require("./rewards/reward-earned.js");
44
44
  var import_skeleton = require("./skeleton.js");
45
45
  var import_textarea = require("./textarea.js");
46
46
  var import_transaction_dialog = require("./transaction-dialog.js");
47
- var import_transaction_done = require("./transaction-done.js");
47
+ var import_transaction_success = require("./transaction-success.js");
48
48
  var import_cn = require("../utils/cn.js");
49
49
  var import_explorer_url = require("../utils/explorer-url.js");
50
50
  var import_run_intent_calls = require("../utils/run-intent-calls.js");
51
51
  var import_time = require("../utils/time.js");
52
+ var import_success_messages = require("../utils/success-messages.js");
52
53
  var import_use_comments = require("../utils/use-comments.js");
53
54
  var import_use_transaction = require("../utils/use-transaction.js");
54
55
  const MAX_LEN = 1e3;
@@ -286,13 +287,13 @@ function CommentsSection({ contract, tokenId, className }) {
286
287
  }
287
288
  ),
288
289
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_transaction_dialog.TransactionDialog, { tx, title: "Comment", workingLabel: "Posting your comment\u2026", firstStepLabel: "Prepare comment", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
289
- import_transaction_done.TransactionDone,
290
+ import_transaction_success.TransactionSuccess,
290
291
  {
291
- tx,
292
292
  name: "Comment",
293
- title: "Comment posted!",
294
- description: "Your comment is onchain and will appear here once indexed (~30s).",
295
- footer: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_reward_earned.RewardEarned, { actionType: "comment" })
293
+ ...import_success_messages.successMessages.commented(),
294
+ txHash: tx.txHash,
295
+ actions: [{ label: "Done", onClick: tx.reset }],
296
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_reward_earned.RewardEarned, { actionType: "comment" })
296
297
  }
297
298
  ) })
298
299
  ] });