@medialane/ui 0.98.0 → 0.99.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/components/community-rewards-section.cjs +12 -9
  2. package/dist/components/community-rewards-section.cjs.map +1 -1
  3. package/dist/components/community-rewards-section.js +12 -9
  4. package/dist/components/community-rewards-section.js.map +1 -1
  5. package/dist/components/rewards/badge-shelf.cjs +2 -0
  6. package/dist/components/rewards/badge-shelf.cjs.map +1 -1
  7. package/dist/components/rewards/badge-shelf.d.cts +6 -1
  8. package/dist/components/rewards/badge-shelf.d.ts +6 -1
  9. package/dist/components/rewards/badge-shelf.js +1 -0
  10. package/dist/components/rewards/badge-shelf.js.map +1 -1
  11. package/dist/components/rewards/badge-unlock-toast-content.cjs +49 -0
  12. package/dist/components/rewards/badge-unlock-toast-content.cjs.map +1 -0
  13. package/dist/components/rewards/badge-unlock-toast-content.d.cts +11 -0
  14. package/dist/components/rewards/badge-unlock-toast-content.d.ts +11 -0
  15. package/dist/components/rewards/badge-unlock-toast-content.js +25 -0
  16. package/dist/components/rewards/badge-unlock-toast-content.js.map +1 -0
  17. package/dist/components/rewards/journey-path.cjs +77 -0
  18. package/dist/components/rewards/journey-path.cjs.map +1 -0
  19. package/dist/components/rewards/journey-path.d.cts +26 -0
  20. package/dist/components/rewards/journey-path.d.ts +26 -0
  21. package/dist/components/rewards/journey-path.js +53 -0
  22. package/dist/components/rewards/journey-path.js.map +1 -0
  23. package/dist/components/rewards/leaderboard-table.cjs +1 -1
  24. package/dist/components/rewards/leaderboard-table.cjs.map +1 -1
  25. package/dist/components/rewards/leaderboard-table.js +1 -1
  26. package/dist/components/rewards/leaderboard-table.js.map +1 -1
  27. package/dist/components/rewards/level-badge.cjs +1 -3
  28. package/dist/components/rewards/level-badge.cjs.map +1 -1
  29. package/dist/components/rewards/level-badge.d.cts +4 -2
  30. package/dist/components/rewards/level-badge.d.ts +4 -2
  31. package/dist/components/rewards/level-badge.js +1 -3
  32. package/dist/components/rewards/level-badge.js.map +1 -1
  33. package/dist/components/rewards/level-up-celebration.cjs +71 -0
  34. package/dist/components/rewards/level-up-celebration.cjs.map +1 -0
  35. package/dist/components/rewards/level-up-celebration.d.cts +16 -0
  36. package/dist/components/rewards/level-up-celebration.d.ts +16 -0
  37. package/dist/components/rewards/level-up-celebration.js +47 -0
  38. package/dist/components/rewards/level-up-celebration.js.map +1 -0
  39. package/dist/components/rewards/reward-toast.cjs +20 -2
  40. package/dist/components/rewards/reward-toast.cjs.map +1 -1
  41. package/dist/components/rewards/reward-toast.d.cts +6 -2
  42. package/dist/components/rewards/reward-toast.d.ts +6 -2
  43. package/dist/components/rewards/reward-toast.js +20 -2
  44. package/dist/components/rewards/reward-toast.js.map +1 -1
  45. package/dist/components/rewards/use-rewards-celebrations.cjs +70 -0
  46. package/dist/components/rewards/use-rewards-celebrations.cjs.map +1 -0
  47. package/dist/components/rewards/use-rewards-celebrations.d.cts +25 -0
  48. package/dist/components/rewards/use-rewards-celebrations.d.ts +25 -0
  49. package/dist/components/rewards/use-rewards-celebrations.js +46 -0
  50. package/dist/components/rewards/use-rewards-celebrations.js.map +1 -0
  51. package/dist/components/rewards/xp-toast-content.cjs +23 -18
  52. package/dist/components/rewards/xp-toast-content.cjs.map +1 -1
  53. package/dist/components/rewards/xp-toast-content.d.cts +7 -1
  54. package/dist/components/rewards/xp-toast-content.d.ts +7 -1
  55. package/dist/components/rewards/xp-toast-content.js +23 -18
  56. package/dist/components/rewards/xp-toast-content.js.map +1 -1
  57. package/dist/index.cjs +14 -2
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.d.cts +5 -1
  60. package/dist/index.d.ts +5 -1
  61. package/dist/index.js +9 -1
  62. package/dist/index.js.map +1 -1
  63. package/package.json +1 -1
@@ -42,11 +42,6 @@ const EARN_ACTIONS = [
42
42
  { icon: import_lucide_react.ShoppingBag, label: "Trade" },
43
43
  { icon: import_lucide_react.MessageSquare, label: "Engage" }
44
44
  ];
45
- const INFO_TILES = [
46
- { value: "50", label: "Levels" },
47
- { value: "XP", label: "Every action" },
48
- { value: "Fund", label: "Distribution" }
49
- ];
50
45
  function CommunityRewardsSection({
51
46
  entries,
52
47
  isLoading = false,
@@ -60,10 +55,18 @@ function CommunityRewardsSection({
60
55
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "mt-4 text-2xl font-bold tracking-tight leading-tight", children: "Community Rewards" }),
61
56
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1.5 text-sm text-muted-foreground leading-relaxed", children: "Earn XP. Share the Creator's Fund." })
62
57
  ] }),
63
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-3 divide-x divide-brand-orange/20 border-y border-brand-orange/20 py-4", children: INFO_TILES.map(({ value, label }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center text-center gap-1 px-2", children: [
64
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xl font-black tabular-nums", children: value }),
65
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] text-muted-foreground leading-tight", children: label })
66
- ] }, label)) }),
58
+ !isLoading && entries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "border-y border-brand-orange/20 py-3", children: [
59
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Recently active" }),
60
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex -space-x-2", children: entries.slice(0, 5).map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
61
+ "span",
62
+ {
63
+ title: `${entry.totalXp.toLocaleString()} XP`,
64
+ className: "flex h-7 w-7 items-center justify-center rounded-full border-2 border-background bg-brand-orange/15 text-[9px] font-bold text-brand-orange",
65
+ children: entry.address.slice(2, 4).toUpperCase()
66
+ },
67
+ entry.address
68
+ )) })
69
+ ] }),
67
70
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-x-5 gap-y-2", children: EARN_ACTIONS.map(({ icon: Icon, label }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
68
71
  "span",
69
72
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/community-rewards-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight, Zap, Palette, ShoppingBag, MessageSquare } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\n\nexport interface CommunityRewardsEntry {\n address: string;\n totalXp: number;\n}\n\nexport interface CommunityRewardsSectionProps {\n entries: CommunityRewardsEntry[];\n isLoading?: boolean;\n rewardsHref: string;\n creatorHref: (address: string) => string;\n}\n\nconst EARN_ACTIONS = [\n { icon: Zap, label: \"Mint\" },\n { icon: Palette, label: \"Create\" },\n { icon: ShoppingBag, label: \"Trade\" },\n { icon: MessageSquare, label: \"Engage\" },\n];\n\nconst INFO_TILES = [\n { value: \"50\", label: \"Levels\" },\n { value: \"XP\", label: \"Every action\" },\n { value: \"Fund\", label: \"Distribution\" },\n];\n\nexport function CommunityRewardsSection({\n entries,\n isLoading = false,\n rewardsHref,\n creatorHref,\n}: CommunityRewardsSectionProps) {\n return (\n <section className=\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden grid lg:grid-cols-2 max-lg:divide-y lg:divide-x divide-brand-orange/20\">\n\n {/* Left — info panel */}\n <div className=\"px-7 py-8 sm:px-9 flex flex-col gap-6\">\n <div>\n {/* Creator's Fund eyebrow — shared with CreatorAirdropBanner */}\n <span className=\"text-xs font-bold uppercase tracking-widest text-brand-orange\">\n Creator&apos;s Fund\n </span>\n <h2 className=\"mt-4 text-2xl font-bold tracking-tight leading-tight\">\n Community Rewards\n </h2>\n <p className=\"mt-1.5 text-sm text-muted-foreground leading-relaxed\">\n Earn XP. Share the Creator&apos;s Fund.\n </p>\n </div>\n\n {/* Info valueshairline-divided row */}\n <div className=\"grid grid-cols-3 divide-x divide-brand-orange/20 border-y border-brand-orange/20 py-4\">\n {INFO_TILES.map(({ value, label }) => (\n <div key={label} className=\"flex flex-col items-center text-center gap-1 px-2\">\n <span className=\"text-xl font-black tabular-nums\">{value}</span>\n <span className=\"text-[10px] text-muted-foreground leading-tight\">{label}</span>\n </div>\n ))}\n </div>\n\n {/* Earn actions — plain text row */}\n <div className=\"flex flex-wrap gap-x-5 gap-y-2\">\n {EARN_ACTIONS.map(({ icon: Icon, label }) => (\n <span\n key={label}\n className=\"flex items-center gap-1.5 text-xs font-medium text-muted-foreground\"\n >\n <Icon className=\"h-3 w-3 text-brand-orange/70\" />\n {label}\n </span>\n ))}\n </div>\n\n <Link\n href={rewardsHref}\n className=\"mt-auto inline-flex items-center justify-center gap-2 rounded-xl bg-brand-orange px-6 py-3 text-sm font-semibold text-white transition-all hover:brightness-110 active:scale-[0.98]\"\n >\n Start earning XP\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n {/* Right — member cards */}\n <div className=\"p-5 sm:p-6\">\n {!isLoading && entries.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {entries.slice(0, 4).map((entry) => (\n <Link\n key={entry.address}\n href={creatorHref(entry.address)}\n className=\"group relative rounded-xl bg-card dark:bg-muted/30 hover:bg-card/70 dark:hover:bg-muted/50 overflow-hidden transition-colors flex flex-col justify-between p-4\"\n >\n <div className=\"absolute inset-x-0 top-0 h-0.5 bg-brand-orange/40\" />\n\n {/* XP — hero number */}\n <div className=\"space-y-0.5 pt-1\">\n <p className=\"text-2xl font-black tabular-nums leading-none\">\n {entry.totalXp.toLocaleString()}\n </p>\n <p className=\"text-[11px] text-muted-foreground\">XP earned</p>\n </div>\n\n <AddressDisplay\n address={entry.address}\n chars={4}\n showCopy={false}\n className=\"text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors\"\n />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"min-h-[100px] rounded-xl bg-card dark:bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CQ;AAxCR,kBAAiB;AACjB,0BAAqE;AACrE,6BAA+B;AAc/B,MAAM,eAAe;AAAA,EACnB,EAAE,MAAM,yBAAK,OAAO,OAAO;AAAA,EAC3B,EAAE,MAAM,6BAAS,OAAO,SAAS;AAAA,EACjC,EAAE,MAAM,iCAAa,OAAO,QAAQ;AAAA,EACpC,EAAE,MAAM,mCAAe,OAAO,SAAS;AACzC;AAEA,MAAM,aAAa;AAAA,EACjB,EAAE,OAAO,MAAM,OAAO,SAAS;AAAA,EAC/B,EAAE,OAAO,MAAM,OAAO,eAAe;AAAA,EACrC,EAAE,OAAO,QAAQ,OAAO,eAAe;AACzC;AAEO,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,6CAAC,aAAQ,WAAU,+HAGjB;AAAA,iDAAC,SAAI,WAAU,yCACb;AAAA,mDAAC,SAEC;AAAA,oDAAC,UAAK,WAAU,iEAAgE,4BAEhF;AAAA,QACA,4CAAC,QAAG,WAAU,wDAAuD,+BAErE;AAAA,QACA,4CAAC,OAAE,WAAU,wDAAuD,gDAEpE;AAAA,SACF;AAAA,MAGA,4CAAC,SAAI,WAAU,yFACZ,qBAAW,IAAI,CAAC,EAAE,OAAO,MAAM,MAC9B,6CAAC,SAAgB,WAAU,qDACzB;AAAA,oDAAC,UAAK,WAAU,mCAAmC,iBAAM;AAAA,QACzD,4CAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA,WAFjE,KAGV,CACD,GACH;AAAA,MAGA,4CAAC,SAAI,WAAU,kCACZ,uBAAa,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,MACrC;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,wDAAC,QAAK,WAAU,gCAA+B;AAAA,YAC9C;AAAA;AAAA;AAAA,QAJI;AAAA,MAKP,CACD,GACH;AAAA,MAEA;AAAA,QAAC,YAAAA;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YAEC,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MACtC;AAAA,OACF;AAAA,IAGA,4CAAC,SAAI,WAAU,cACZ,WAAC,aAAa,QAAQ,SAAS,IAC9B,4CAAC,SAAI,WAAU,iCACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QAEC,MAAM,YAAY,MAAM,OAAO;AAAA,QAC/B,WAAU;AAAA,QAEV;AAAA,sDAAC,SAAI,WAAU,qDAAoD;AAAA,UAGnE,6CAAC,SAAI,WAAU,oBACb;AAAA,wDAAC,OAAE,WAAU,iDACV,gBAAM,QAAQ,eAAe,GAChC;AAAA,YACA,4CAAC,OAAE,WAAU,qCAAoC,uBAAS;AAAA,aAC5D;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM;AAAA,cACf,OAAO;AAAA,cACP,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,MAnBK,MAAM;AAAA,IAoBb,CACD,GACH,IAEA,4CAAC,SAAI,WAAU,iCACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,4CAAC,SAAY,WAAU,qEAAb,CAA+E,CAC1F,GACH,GAEJ;AAAA,KACF;AAEJ;","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/community-rewards-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight, Zap, Palette, ShoppingBag, MessageSquare } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\n\nexport interface CommunityRewardsEntry {\n address: string;\n totalXp: number;\n}\n\nexport interface CommunityRewardsSectionProps {\n entries: CommunityRewardsEntry[];\n isLoading?: boolean;\n rewardsHref: string;\n creatorHref: (address: string) => string;\n}\n\nconst EARN_ACTIONS = [\n { icon: Zap, label: \"Mint\" },\n { icon: Palette, label: \"Create\" },\n { icon: ShoppingBag, label: \"Trade\" },\n { icon: MessageSquare, label: \"Engage\" },\n];\n\nexport function CommunityRewardsSection({\n entries,\n isLoading = false,\n rewardsHref,\n creatorHref,\n}: CommunityRewardsSectionProps) {\n return (\n <section className=\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden grid lg:grid-cols-2 max-lg:divide-y lg:divide-x divide-brand-orange/20\">\n\n {/* Left — info panel */}\n <div className=\"px-7 py-8 sm:px-9 flex flex-col gap-6\">\n <div>\n {/* Creator's Fund eyebrow — shared with CreatorAirdropBanner */}\n <span className=\"text-xs font-bold uppercase tracking-widest text-brand-orange\">\n Creator&apos;s Fund\n </span>\n <h2 className=\"mt-4 text-2xl font-bold tracking-tight leading-tight\">\n Community Rewards\n </h2>\n <p className=\"mt-1.5 text-sm text-muted-foreground leading-relaxed\">\n Earn XP. Share the Creator&apos;s Fund.\n </p>\n </div>\n\n {/* Recently activelive rail sourced from the same entries as the\n member cards on the right, no rank/podium framing. */}\n {!isLoading && entries.length > 0 && (\n <div className=\"border-y border-brand-orange/20 py-3\">\n <p className=\"text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-2\">\n Recently active\n </p>\n <div className=\"flex -space-x-2\">\n {entries.slice(0, 5).map((entry) => (\n <span\n key={entry.address}\n title={`${entry.totalXp.toLocaleString()} XP`}\n className=\"flex h-7 w-7 items-center justify-center rounded-full border-2 border-background bg-brand-orange/15 text-[9px] font-bold text-brand-orange\"\n >\n {entry.address.slice(2, 4).toUpperCase()}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {/* Earn actions — plain text row */}\n <div className=\"flex flex-wrap gap-x-5 gap-y-2\">\n {EARN_ACTIONS.map(({ icon: Icon, label }) => (\n <span\n key={label}\n className=\"flex items-center gap-1.5 text-xs font-medium text-muted-foreground\"\n >\n <Icon className=\"h-3 w-3 text-brand-orange/70\" />\n {label}\n </span>\n ))}\n </div>\n\n <Link\n href={rewardsHref}\n className=\"mt-auto inline-flex items-center justify-center gap-2 rounded-xl bg-brand-orange px-6 py-3 text-sm font-semibold text-white transition-all hover:brightness-110 active:scale-[0.98]\"\n >\n Start earning XP\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n {/* Right — member cards */}\n <div className=\"p-5 sm:p-6\">\n {!isLoading && entries.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {entries.slice(0, 4).map((entry) => (\n <Link\n key={entry.address}\n href={creatorHref(entry.address)}\n className=\"group relative rounded-xl bg-card dark:bg-muted/30 hover:bg-card/70 dark:hover:bg-muted/50 overflow-hidden transition-colors flex flex-col justify-between p-4\"\n >\n <div className=\"absolute inset-x-0 top-0 h-0.5 bg-brand-orange/40\" />\n\n {/* XP — hero number */}\n <div className=\"space-y-0.5 pt-1\">\n <p className=\"text-2xl font-black tabular-nums leading-none\">\n {entry.totalXp.toLocaleString()}\n </p>\n <p className=\"text-[11px] text-muted-foreground\">XP earned</p>\n </div>\n\n <AddressDisplay\n address={entry.address}\n chars={4}\n showCopy={false}\n className=\"text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors\"\n />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"min-h-[100px] rounded-xl bg-card dark:bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCQ;AAlCR,kBAAiB;AACjB,0BAAqE;AACrE,6BAA+B;AAc/B,MAAM,eAAe;AAAA,EACnB,EAAE,MAAM,yBAAK,OAAO,OAAO;AAAA,EAC3B,EAAE,MAAM,6BAAS,OAAO,SAAS;AAAA,EACjC,EAAE,MAAM,iCAAa,OAAO,QAAQ;AAAA,EACpC,EAAE,MAAM,mCAAe,OAAO,SAAS;AACzC;AAEO,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,6CAAC,aAAQ,WAAU,+HAGjB;AAAA,iDAAC,SAAI,WAAU,yCACb;AAAA,mDAAC,SAEC;AAAA,oDAAC,UAAK,WAAU,iEAAgE,4BAEhF;AAAA,QACA,4CAAC,QAAG,WAAU,wDAAuD,+BAErE;AAAA,QACA,4CAAC,OAAE,WAAU,wDAAuD,gDAEpE;AAAA,SACF;AAAA,MAIC,CAAC,aAAa,QAAQ,SAAS,KAC9B,6CAAC,SAAI,WAAU,wCACb;AAAA,oDAAC,OAAE,WAAU,8EAA6E,6BAE1F;AAAA,QACA,4CAAC,SAAI,WAAU,mBACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,GAAG,MAAM,QAAQ,eAAe,CAAC;AAAA,YACxC,WAAU;AAAA,YAET,gBAAM,QAAQ,MAAM,GAAG,CAAC,EAAE,YAAY;AAAA;AAAA,UAJlC,MAAM;AAAA,QAKb,CACD,GACH;AAAA,SACF;AAAA,MAIF,4CAAC,SAAI,WAAU,kCACZ,uBAAa,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,MACrC;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,wDAAC,QAAK,WAAU,gCAA+B;AAAA,YAC9C;AAAA;AAAA;AAAA,QAJI;AAAA,MAKP,CACD,GACH;AAAA,MAEA;AAAA,QAAC,YAAAA;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YAEC,4CAAC,kCAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MACtC;AAAA,OACF;AAAA,IAGA,4CAAC,SAAI,WAAU,cACZ,WAAC,aAAa,QAAQ,SAAS,IAC9B,4CAAC,SAAI,WAAU,iCACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QAEC,MAAM,YAAY,MAAM,OAAO;AAAA,QAC/B,WAAU;AAAA,QAEV;AAAA,sDAAC,SAAI,WAAU,qDAAoD;AAAA,UAGnE,6CAAC,SAAI,WAAU,oBACb;AAAA,wDAAC,OAAE,WAAU,iDACV,gBAAM,QAAQ,eAAe,GAChC;AAAA,YACA,4CAAC,OAAE,WAAU,qCAAoC,uBAAS;AAAA,aAC5D;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM;AAAA,cACf,OAAO;AAAA,cACP,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,MAnBK,MAAM;AAAA,IAoBb,CACD,GACH,IAEA,4CAAC,SAAI,WAAU,iCACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,4CAAC,SAAY,WAAU,qEAAb,CAA+E,CAC1F,GACH,GAEJ;AAAA,KACF;AAEJ;","names":["Link"]}
@@ -9,11 +9,6 @@ const EARN_ACTIONS = [
9
9
  { icon: ShoppingBag, label: "Trade" },
10
10
  { icon: MessageSquare, label: "Engage" }
11
11
  ];
12
- const INFO_TILES = [
13
- { value: "50", label: "Levels" },
14
- { value: "XP", label: "Every action" },
15
- { value: "Fund", label: "Distribution" }
16
- ];
17
12
  function CommunityRewardsSection({
18
13
  entries,
19
14
  isLoading = false,
@@ -27,10 +22,18 @@ function CommunityRewardsSection({
27
22
  /* @__PURE__ */ jsx("h2", { className: "mt-4 text-2xl font-bold tracking-tight leading-tight", children: "Community Rewards" }),
28
23
  /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground leading-relaxed", children: "Earn XP. Share the Creator's Fund." })
29
24
  ] }),
30
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 divide-x divide-brand-orange/20 border-y border-brand-orange/20 py-4", children: INFO_TILES.map(({ value, label }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-center gap-1 px-2", children: [
31
- /* @__PURE__ */ jsx("span", { className: "text-xl font-black tabular-nums", children: value }),
32
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground leading-tight", children: label })
33
- ] }, label)) }),
25
+ !isLoading && entries.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-y border-brand-orange/20 py-3", children: [
26
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-2", children: "Recently active" }),
27
+ /* @__PURE__ */ jsx("div", { className: "flex -space-x-2", children: entries.slice(0, 5).map((entry) => /* @__PURE__ */ jsx(
28
+ "span",
29
+ {
30
+ title: `${entry.totalXp.toLocaleString()} XP`,
31
+ className: "flex h-7 w-7 items-center justify-center rounded-full border-2 border-background bg-brand-orange/15 text-[9px] font-bold text-brand-orange",
32
+ children: entry.address.slice(2, 4).toUpperCase()
33
+ },
34
+ entry.address
35
+ )) })
36
+ ] }),
34
37
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-x-5 gap-y-2", children: EARN_ACTIONS.map(({ icon: Icon, label }) => /* @__PURE__ */ jsxs(
35
38
  "span",
36
39
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/community-rewards-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight, Zap, Palette, ShoppingBag, MessageSquare } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\n\nexport interface CommunityRewardsEntry {\n address: string;\n totalXp: number;\n}\n\nexport interface CommunityRewardsSectionProps {\n entries: CommunityRewardsEntry[];\n isLoading?: boolean;\n rewardsHref: string;\n creatorHref: (address: string) => string;\n}\n\nconst EARN_ACTIONS = [\n { icon: Zap, label: \"Mint\" },\n { icon: Palette, label: \"Create\" },\n { icon: ShoppingBag, label: \"Trade\" },\n { icon: MessageSquare, label: \"Engage\" },\n];\n\nconst INFO_TILES = [\n { value: \"50\", label: \"Levels\" },\n { value: \"XP\", label: \"Every action\" },\n { value: \"Fund\", label: \"Distribution\" },\n];\n\nexport function CommunityRewardsSection({\n entries,\n isLoading = false,\n rewardsHref,\n creatorHref,\n}: CommunityRewardsSectionProps) {\n return (\n <section className=\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden grid lg:grid-cols-2 max-lg:divide-y lg:divide-x divide-brand-orange/20\">\n\n {/* Left — info panel */}\n <div className=\"px-7 py-8 sm:px-9 flex flex-col gap-6\">\n <div>\n {/* Creator's Fund eyebrow — shared with CreatorAirdropBanner */}\n <span className=\"text-xs font-bold uppercase tracking-widest text-brand-orange\">\n Creator&apos;s Fund\n </span>\n <h2 className=\"mt-4 text-2xl font-bold tracking-tight leading-tight\">\n Community Rewards\n </h2>\n <p className=\"mt-1.5 text-sm text-muted-foreground leading-relaxed\">\n Earn XP. Share the Creator&apos;s Fund.\n </p>\n </div>\n\n {/* Info valueshairline-divided row */}\n <div className=\"grid grid-cols-3 divide-x divide-brand-orange/20 border-y border-brand-orange/20 py-4\">\n {INFO_TILES.map(({ value, label }) => (\n <div key={label} className=\"flex flex-col items-center text-center gap-1 px-2\">\n <span className=\"text-xl font-black tabular-nums\">{value}</span>\n <span className=\"text-[10px] text-muted-foreground leading-tight\">{label}</span>\n </div>\n ))}\n </div>\n\n {/* Earn actions — plain text row */}\n <div className=\"flex flex-wrap gap-x-5 gap-y-2\">\n {EARN_ACTIONS.map(({ icon: Icon, label }) => (\n <span\n key={label}\n className=\"flex items-center gap-1.5 text-xs font-medium text-muted-foreground\"\n >\n <Icon className=\"h-3 w-3 text-brand-orange/70\" />\n {label}\n </span>\n ))}\n </div>\n\n <Link\n href={rewardsHref}\n className=\"mt-auto inline-flex items-center justify-center gap-2 rounded-xl bg-brand-orange px-6 py-3 text-sm font-semibold text-white transition-all hover:brightness-110 active:scale-[0.98]\"\n >\n Start earning XP\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n {/* Right — member cards */}\n <div className=\"p-5 sm:p-6\">\n {!isLoading && entries.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {entries.slice(0, 4).map((entry) => (\n <Link\n key={entry.address}\n href={creatorHref(entry.address)}\n className=\"group relative rounded-xl bg-card dark:bg-muted/30 hover:bg-card/70 dark:hover:bg-muted/50 overflow-hidden transition-colors flex flex-col justify-between p-4\"\n >\n <div className=\"absolute inset-x-0 top-0 h-0.5 bg-brand-orange/40\" />\n\n {/* XP — hero number */}\n <div className=\"space-y-0.5 pt-1\">\n <p className=\"text-2xl font-black tabular-nums leading-none\">\n {entry.totalXp.toLocaleString()}\n </p>\n <p className=\"text-[11px] text-muted-foreground\">XP earned</p>\n </div>\n\n <AddressDisplay\n address={entry.address}\n chars={4}\n showCopy={false}\n className=\"text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors\"\n />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"min-h-[100px] rounded-xl bg-card dark:bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";AA0CQ,SAEE,KAFF;AAxCR,OAAO,UAAU;AACjB,SAAS,YAAY,KAAK,SAAS,aAAa,qBAAqB;AACrE,SAAS,sBAAsB;AAc/B,MAAM,eAAe;AAAA,EACnB,EAAE,MAAM,KAAK,OAAO,OAAO;AAAA,EAC3B,EAAE,MAAM,SAAS,OAAO,SAAS;AAAA,EACjC,EAAE,MAAM,aAAa,OAAO,QAAQ;AAAA,EACpC,EAAE,MAAM,eAAe,OAAO,SAAS;AACzC;AAEA,MAAM,aAAa;AAAA,EACjB,EAAE,OAAO,MAAM,OAAO,SAAS;AAAA,EAC/B,EAAE,OAAO,MAAM,OAAO,eAAe;AAAA,EACrC,EAAE,OAAO,QAAQ,OAAO,eAAe;AACzC;AAEO,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,qBAAC,aAAQ,WAAU,+HAGjB;AAAA,yBAAC,SAAI,WAAU,yCACb;AAAA,2BAAC,SAEC;AAAA,4BAAC,UAAK,WAAU,iEAAgE,4BAEhF;AAAA,QACA,oBAAC,QAAG,WAAU,wDAAuD,+BAErE;AAAA,QACA,oBAAC,OAAE,WAAU,wDAAuD,gDAEpE;AAAA,SACF;AAAA,MAGA,oBAAC,SAAI,WAAU,yFACZ,qBAAW,IAAI,CAAC,EAAE,OAAO,MAAM,MAC9B,qBAAC,SAAgB,WAAU,qDACzB;AAAA,4BAAC,UAAK,WAAU,mCAAmC,iBAAM;AAAA,QACzD,oBAAC,UAAK,WAAU,mDAAmD,iBAAM;AAAA,WAFjE,KAGV,CACD,GACH;AAAA,MAGA,oBAAC,SAAI,WAAU,kCACZ,uBAAa,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,MACrC;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,gCAAC,QAAK,WAAU,gCAA+B;AAAA,YAC9C;AAAA;AAAA;AAAA,QAJI;AAAA,MAKP,CACD,GACH;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YAEC,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MACtC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,cACZ,WAAC,aAAa,QAAQ,SAAS,IAC9B,oBAAC,SAAI,WAAU,iCACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,YAAY,MAAM,OAAO;AAAA,QAC/B,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAU,qDAAoD;AAAA,UAGnE,qBAAC,SAAI,WAAU,oBACb;AAAA,gCAAC,OAAE,WAAU,iDACV,gBAAM,QAAQ,eAAe,GAChC;AAAA,YACA,oBAAC,OAAE,WAAU,qCAAoC,uBAAS;AAAA,aAC5D;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM;AAAA,cACf,OAAO;AAAA,cACP,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,MAnBK,MAAM;AAAA,IAoBb,CACD,GACH,IAEA,oBAAC,SAAI,WAAU,iCACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,oBAAC,SAAY,WAAU,qEAAb,CAA+E,CAC1F,GACH,GAEJ;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/community-rewards-section.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"next/link\";\nimport { ArrowRight, Zap, Palette, ShoppingBag, MessageSquare } from \"lucide-react\";\nimport { AddressDisplay } from \"./address-display.js\";\n\nexport interface CommunityRewardsEntry {\n address: string;\n totalXp: number;\n}\n\nexport interface CommunityRewardsSectionProps {\n entries: CommunityRewardsEntry[];\n isLoading?: boolean;\n rewardsHref: string;\n creatorHref: (address: string) => string;\n}\n\nconst EARN_ACTIONS = [\n { icon: Zap, label: \"Mint\" },\n { icon: Palette, label: \"Create\" },\n { icon: ShoppingBag, label: \"Trade\" },\n { icon: MessageSquare, label: \"Engage\" },\n];\n\nexport function CommunityRewardsSection({\n entries,\n isLoading = false,\n rewardsHref,\n creatorHref,\n}: CommunityRewardsSectionProps) {\n return (\n <section className=\"rounded-2xl bg-muted/50 dark:bg-card overflow-hidden grid lg:grid-cols-2 max-lg:divide-y lg:divide-x divide-brand-orange/20\">\n\n {/* Left — info panel */}\n <div className=\"px-7 py-8 sm:px-9 flex flex-col gap-6\">\n <div>\n {/* Creator's Fund eyebrow — shared with CreatorAirdropBanner */}\n <span className=\"text-xs font-bold uppercase tracking-widest text-brand-orange\">\n Creator&apos;s Fund\n </span>\n <h2 className=\"mt-4 text-2xl font-bold tracking-tight leading-tight\">\n Community Rewards\n </h2>\n <p className=\"mt-1.5 text-sm text-muted-foreground leading-relaxed\">\n Earn XP. Share the Creator&apos;s Fund.\n </p>\n </div>\n\n {/* Recently activelive rail sourced from the same entries as the\n member cards on the right, no rank/podium framing. */}\n {!isLoading && entries.length > 0 && (\n <div className=\"border-y border-brand-orange/20 py-3\">\n <p className=\"text-[10px] font-bold uppercase tracking-widest text-muted-foreground mb-2\">\n Recently active\n </p>\n <div className=\"flex -space-x-2\">\n {entries.slice(0, 5).map((entry) => (\n <span\n key={entry.address}\n title={`${entry.totalXp.toLocaleString()} XP`}\n className=\"flex h-7 w-7 items-center justify-center rounded-full border-2 border-background bg-brand-orange/15 text-[9px] font-bold text-brand-orange\"\n >\n {entry.address.slice(2, 4).toUpperCase()}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {/* Earn actions — plain text row */}\n <div className=\"flex flex-wrap gap-x-5 gap-y-2\">\n {EARN_ACTIONS.map(({ icon: Icon, label }) => (\n <span\n key={label}\n className=\"flex items-center gap-1.5 text-xs font-medium text-muted-foreground\"\n >\n <Icon className=\"h-3 w-3 text-brand-orange/70\" />\n {label}\n </span>\n ))}\n </div>\n\n <Link\n href={rewardsHref}\n className=\"mt-auto inline-flex items-center justify-center gap-2 rounded-xl bg-brand-orange px-6 py-3 text-sm font-semibold text-white transition-all hover:brightness-110 active:scale-[0.98]\"\n >\n Start earning XP\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </Link>\n </div>\n\n {/* Right — member cards */}\n <div className=\"p-5 sm:p-6\">\n {!isLoading && entries.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {entries.slice(0, 4).map((entry) => (\n <Link\n key={entry.address}\n href={creatorHref(entry.address)}\n className=\"group relative rounded-xl bg-card dark:bg-muted/30 hover:bg-card/70 dark:hover:bg-muted/50 overflow-hidden transition-colors flex flex-col justify-between p-4\"\n >\n <div className=\"absolute inset-x-0 top-0 h-0.5 bg-brand-orange/40\" />\n\n {/* XP — hero number */}\n <div className=\"space-y-0.5 pt-1\">\n <p className=\"text-2xl font-black tabular-nums leading-none\">\n {entry.totalXp.toLocaleString()}\n </p>\n <p className=\"text-[11px] text-muted-foreground\">XP earned</p>\n </div>\n\n <AddressDisplay\n address={entry.address}\n chars={4}\n showCopy={false}\n className=\"text-xs font-medium text-muted-foreground group-hover:text-foreground transition-colors\"\n />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 h-full\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"min-h-[100px] rounded-xl bg-card dark:bg-muted/30 animate-pulse\" />\n ))}\n </div>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":";AAoCQ,SAEE,KAFF;AAlCR,OAAO,UAAU;AACjB,SAAS,YAAY,KAAK,SAAS,aAAa,qBAAqB;AACrE,SAAS,sBAAsB;AAc/B,MAAM,eAAe;AAAA,EACnB,EAAE,MAAM,KAAK,OAAO,OAAO;AAAA,EAC3B,EAAE,MAAM,SAAS,OAAO,SAAS;AAAA,EACjC,EAAE,MAAM,aAAa,OAAO,QAAQ;AAAA,EACpC,EAAE,MAAM,eAAe,OAAO,SAAS;AACzC;AAEO,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,qBAAC,aAAQ,WAAU,+HAGjB;AAAA,yBAAC,SAAI,WAAU,yCACb;AAAA,2BAAC,SAEC;AAAA,4BAAC,UAAK,WAAU,iEAAgE,4BAEhF;AAAA,QACA,oBAAC,QAAG,WAAU,wDAAuD,+BAErE;AAAA,QACA,oBAAC,OAAE,WAAU,wDAAuD,gDAEpE;AAAA,SACF;AAAA,MAIC,CAAC,aAAa,QAAQ,SAAS,KAC9B,qBAAC,SAAI,WAAU,wCACb;AAAA,4BAAC,OAAE,WAAU,8EAA6E,6BAE1F;AAAA,QACA,oBAAC,SAAI,WAAU,mBACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,UAAC;AAAA;AAAA,YAEC,OAAO,GAAG,MAAM,QAAQ,eAAe,CAAC;AAAA,YACxC,WAAU;AAAA,YAET,gBAAM,QAAQ,MAAM,GAAG,CAAC,EAAE,YAAY;AAAA;AAAA,UAJlC,MAAM;AAAA,QAKb,CACD,GACH;AAAA,SACF;AAAA,MAIF,oBAAC,SAAI,WAAU,kCACZ,uBAAa,IAAI,CAAC,EAAE,MAAM,MAAM,MAAM,MACrC;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA,gCAAC,QAAK,WAAU,gCAA+B;AAAA,YAC9C;AAAA;AAAA;AAAA,QAJI;AAAA,MAKP,CACD,GACH;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UACX;AAAA;AAAA,YAEC,oBAAC,cAAW,WAAU,eAAc;AAAA;AAAA;AAAA,MACtC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,cACZ,WAAC,aAAa,QAAQ,SAAS,IAC9B,oBAAC,SAAI,WAAU,iCACZ,kBAAQ,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UACxB;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM,YAAY,MAAM,OAAO;AAAA,QAC/B,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAU,qDAAoD;AAAA,UAGnE,qBAAC,SAAI,WAAU,oBACb;AAAA,gCAAC,OAAE,WAAU,iDACV,gBAAM,QAAQ,eAAe,GAChC;AAAA,YACA,oBAAC,OAAE,WAAU,qCAAoC,uBAAS;AAAA,aAC5D;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,MAAM;AAAA,cACf,OAAO;AAAA,cACP,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA;AAAA,MAnBK,MAAM;AAAA,IAoBb,CACD,GACH,IAEA,oBAAC,SAAI,WAAU,iCACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,oBAAC,SAAY,WAAU,qEAAb,CAA+E,CAC1F,GACH,GAEJ;AAAA,KACF;AAEJ;","names":[]}
@@ -29,6 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
30
  var badge_shelf_exports = {};
31
31
  __export(badge_shelf_exports, {
32
+ BadgeIcon: () => BadgeIcon,
32
33
  BadgeShelf: () => BadgeShelf
33
34
  });
34
35
  module.exports = __toCommonJS(badge_shelf_exports);
@@ -85,6 +86,7 @@ function BadgeShelf({ badges, earnedKeys, showLocked = false, className }) {
85
86
  }
86
87
  // Annotate the CommonJS export names for ESM import in node:
87
88
  0 && (module.exports = {
89
+ BadgeIcon,
88
90
  BadgeShelf
89
91
  });
90
92
  //# sourceMappingURL=badge-shelf.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nfunction BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CoB;AA7CpB,mBAAkB;AAElB,gBAAmB;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAEpE,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AAClG,QAAM,CAAC,MAAM,OAAO,IAAI,aAAAA,QAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,4CAAC,UAAK,eAAW,cAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,4CAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,4CAAC,SAAI,eAAW,cAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,eAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,sDAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,4CAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":["React"]}
1
+ {"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nexport function BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CoB;AA7CpB,mBAAkB;AAElB,gBAAmB;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAE7D,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AACzG,QAAM,CAAC,MAAM,OAAO,IAAI,aAAAA,QAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,4CAAC,UAAK,eAAW,cAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,4CAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,4CAAC,SAAI,eAAW,cAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,eAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,sDAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,4CAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":["React"]}
@@ -17,8 +17,13 @@ interface BadgeShelfProps {
17
17
  showLocked?: boolean;
18
18
  className?: string;
19
19
  }
20
+ declare function BadgeIcon({ name, color, className }: {
21
+ name: string;
22
+ color: string;
23
+ className?: string;
24
+ }): react_jsx_runtime.JSX.Element;
20
25
  /** Badge chips with native tooltips. Earned badges render in their color;
21
26
  * locked ones (present in `badges` but not `earnedKeys`) render muted. */
22
27
  declare function BadgeShelf({ badges, earnedKeys, showLocked, className }: BadgeShelfProps): react_jsx_runtime.JSX.Element | null;
23
28
 
24
- export { BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
29
+ export { BadgeIcon, BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
@@ -17,8 +17,13 @@ interface BadgeShelfProps {
17
17
  showLocked?: boolean;
18
18
  className?: string;
19
19
  }
20
+ declare function BadgeIcon({ name, color, className }: {
21
+ name: string;
22
+ color: string;
23
+ className?: string;
24
+ }): react_jsx_runtime.JSX.Element;
20
25
  /** Badge chips with native tooltips. Earned badges render in their color;
21
26
  * locked ones (present in `badges` but not `earnedKeys`) render muted. */
22
27
  declare function BadgeShelf({ badges, earnedKeys, showLocked, className }: BadgeShelfProps): react_jsx_runtime.JSX.Element | null;
23
28
 
24
- export { BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
29
+ export { BadgeIcon, BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
@@ -51,6 +51,7 @@ function BadgeShelf({ badges, earnedKeys, showLocked = false, className }) {
51
51
  }) });
52
52
  }
53
53
  export {
54
+ BadgeIcon,
54
55
  BadgeShelf
55
56
  };
56
57
  //# sourceMappingURL=badge-shelf.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nfunction BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AA+CoB,cAgBV,YAhBU;AA7CpB,OAAO,WAAW;AAElB,SAAS,UAAU;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAEpE,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AAClG,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,oBAAC,UAAK,WAAW,GAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,oBAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,oBAAC,SAAI,WAAW,GAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,8BAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,oBAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nexport function BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AA+CoB,cAgBV,YAhBU;AA7CpB,OAAO,WAAW;AAElB,SAAS,UAAU;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAE7D,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AACzG,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,oBAAC,UAAK,WAAW,GAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,oBAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,oBAAC,SAAI,WAAW,GAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,8BAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,oBAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var badge_unlock_toast_content_exports = {};
20
+ __export(badge_unlock_toast_content_exports, {
21
+ BadgeUnlockToastContent: () => BadgeUnlockToastContent
22
+ });
23
+ module.exports = __toCommonJS(badge_unlock_toast_content_exports);
24
+ var import_jsx_runtime = require("react/jsx-runtime");
25
+ var import_badge_shelf = require("./badge-shelf.js");
26
+ function BadgeUnlockToastContent({ badge }) {
27
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
28
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
29
+ "span",
30
+ {
31
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border",
32
+ style: { borderColor: `${badge.color}60`, backgroundColor: `${badge.color}18` },
33
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_badge_shelf.BadgeIcon, { name: badge.icon, color: badge.color, className: "h-4 w-4" })
34
+ }
35
+ ),
36
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0", children: [
37
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "truncate text-sm font-semibold", children: [
38
+ "Badge earned \xB7 ",
39
+ badge.name
40
+ ] }),
41
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground truncate", children: badge.description })
42
+ ] })
43
+ ] });
44
+ }
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ BadgeUnlockToastContent
48
+ });
49
+ //# sourceMappingURL=badge-unlock-toast-content.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/badge-unlock-toast-content.tsx"],"sourcesContent":["import { BadgeIcon } from \"./badge-shelf.js\";\nimport type { BadgeShelfBadge } from \"./badge-shelf.js\";\n\nexport interface BadgeUnlockToastContentProps {\n badge: BadgeShelfBadge;\n}\n\n/** Toast body for a newly-earned badge: icon, name, description — the\n * badge equivalent of XpToastContent. */\nexport function BadgeUnlockToastContent({ badge }: BadgeUnlockToastContentProps) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border\"\n style={{ borderColor: `${badge.color}60`, backgroundColor: `${badge.color}18` }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold\">Badge earned · {badge.name}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{badge.description}</p>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBQ;AAhBR,yBAA0B;AASnB,SAAS,wBAAwB,EAAE,MAAM,GAAiC;AAC/E,SACE,6CAAC,SAAI,WAAU,6BACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,GAAG,MAAM,KAAK,MAAM,iBAAiB,GAAG,MAAM,KAAK,KAAK;AAAA,QAE9E,sDAAC,gCAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,WAAU;AAAA;AAAA,IACvE;AAAA,IACA,6CAAC,SAAI,WAAU,WACb;AAAA,mDAAC,OAAE,WAAU,kCAAiC;AAAA;AAAA,QAAgB,MAAM;AAAA,SAAK;AAAA,MACzE,4CAAC,OAAE,WAAU,0CAA0C,gBAAM,aAAY;AAAA,OAC3E;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,11 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { BadgeShelfBadge } from './badge-shelf.cjs';
3
+
4
+ interface BadgeUnlockToastContentProps {
5
+ badge: BadgeShelfBadge;
6
+ }
7
+ /** Toast body for a newly-earned badge: icon, name, description — the
8
+ * badge equivalent of XpToastContent. */
9
+ declare function BadgeUnlockToastContent({ badge }: BadgeUnlockToastContentProps): react_jsx_runtime.JSX.Element;
10
+
11
+ export { BadgeUnlockToastContent, type BadgeUnlockToastContentProps };
@@ -0,0 +1,11 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { BadgeShelfBadge } from './badge-shelf.js';
3
+
4
+ interface BadgeUnlockToastContentProps {
5
+ badge: BadgeShelfBadge;
6
+ }
7
+ /** Toast body for a newly-earned badge: icon, name, description — the
8
+ * badge equivalent of XpToastContent. */
9
+ declare function BadgeUnlockToastContent({ badge }: BadgeUnlockToastContentProps): react_jsx_runtime.JSX.Element;
10
+
11
+ export { BadgeUnlockToastContent, type BadgeUnlockToastContentProps };
@@ -0,0 +1,25 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { BadgeIcon } from "./badge-shelf.js";
3
+ function BadgeUnlockToastContent({ badge }) {
4
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
5
+ /* @__PURE__ */ jsx(
6
+ "span",
7
+ {
8
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border",
9
+ style: { borderColor: `${badge.color}60`, backgroundColor: `${badge.color}18` },
10
+ children: /* @__PURE__ */ jsx(BadgeIcon, { name: badge.icon, color: badge.color, className: "h-4 w-4" })
11
+ }
12
+ ),
13
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
14
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-sm font-semibold", children: [
15
+ "Badge earned \xB7 ",
16
+ badge.name
17
+ ] }),
18
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: badge.description })
19
+ ] })
20
+ ] });
21
+ }
22
+ export {
23
+ BadgeUnlockToastContent
24
+ };
25
+ //# sourceMappingURL=badge-unlock-toast-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/badge-unlock-toast-content.tsx"],"sourcesContent":["import { BadgeIcon } from \"./badge-shelf.js\";\nimport type { BadgeShelfBadge } from \"./badge-shelf.js\";\n\nexport interface BadgeUnlockToastContentProps {\n badge: BadgeShelfBadge;\n}\n\n/** Toast body for a newly-earned badge: icon, name, description — the\n * badge equivalent of XpToastContent. */\nexport function BadgeUnlockToastContent({ badge }: BadgeUnlockToastContentProps) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border\"\n style={{ borderColor: `${badge.color}60`, backgroundColor: `${badge.color}18` }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold\">Badge earned · {badge.name}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{badge.description}</p>\n </div>\n </div>\n );\n}\n"],"mappings":"AAgBQ,cAGA,YAHA;AAhBR,SAAS,iBAAiB;AASnB,SAAS,wBAAwB,EAAE,MAAM,GAAiC;AAC/E,SACE,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,GAAG,MAAM,KAAK,MAAM,iBAAiB,GAAG,MAAM,KAAK,KAAK;AAAA,QAE9E,8BAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,WAAU;AAAA;AAAA,IACvE;AAAA,IACA,qBAAC,SAAI,WAAU,WACb;AAAA,2BAAC,OAAE,WAAU,kCAAiC;AAAA;AAAA,QAAgB,MAAM;AAAA,SAAK;AAAA,MACzE,oBAAC,OAAE,WAAU,0CAA0C,gBAAM,aAAY;AAAA,OAC3E;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var journey_path_exports = {};
20
+ __export(journey_path_exports, {
21
+ JourneyPath: () => JourneyPath
22
+ });
23
+ module.exports = __toCommonJS(journey_path_exports);
24
+ var import_jsx_runtime = require("react/jsx-runtime");
25
+ var import_cn = require("../../utils/cn.js");
26
+ function stateFor(step, index, steps, breakdown) {
27
+ if ((breakdown[step.actionType] ?? 0) > 0) return "done";
28
+ const firstNotDone = steps.findIndex((s) => (breakdown[s.actionType] ?? 0) <= 0);
29
+ return index === firstNotDone ? "current" : "upcoming";
30
+ }
31
+ function JourneyPath({ steps, breakdown = {}, className }) {
32
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: (0, import_cn.cn)("flex flex-col gap-1", className), children: steps.map((step, i) => {
33
+ const state = stateFor(step, i, steps, breakdown);
34
+ const Icon = step.icon;
35
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "relative flex items-center gap-3", children: [
36
+ i < steps.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
37
+ "span",
38
+ {
39
+ "aria-hidden": true,
40
+ className: (0, import_cn.cn)(
41
+ "absolute left-[15px] top-8 h-[calc(100%-8px)] w-px",
42
+ state === "done" ? "bg-brand-rose/50" : "bg-border"
43
+ )
44
+ }
45
+ ),
46
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
47
+ "a",
48
+ {
49
+ href: step.href,
50
+ className: (0, import_cn.cn)(
51
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border transition-colors",
52
+ state === "done" && "border-brand-rose/40 bg-brand-rose/15 text-brand-rose",
53
+ state === "current" && "border-brand-orange/60 bg-brand-orange/10 text-brand-orange",
54
+ state === "upcoming" && "border-border text-muted-foreground/50"
55
+ ),
56
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5" })
57
+ }
58
+ ),
59
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
60
+ "a",
61
+ {
62
+ href: step.href,
63
+ className: (0, import_cn.cn)(
64
+ "flex-1 rounded-lg py-1.5 text-sm font-semibold transition-colors hover:text-foreground",
65
+ state === "upcoming" ? "text-muted-foreground/60" : "text-foreground"
66
+ ),
67
+ children: step.label
68
+ }
69
+ )
70
+ ] }, step.actionType);
71
+ }) });
72
+ }
73
+ // Annotate the CommonJS export names for ESM import in node:
74
+ 0 && (module.exports = {
75
+ JourneyPath
76
+ });
77
+ //# sourceMappingURL=journey-path.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/journey-path.tsx"],"sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface JourneyStep {\n /** Matches a key in the rewards breakdown (e.g. \"mint_asset\"). */\n actionType: string;\n label: string;\n href: string;\n icon: ElementType;\n}\n\nexport interface JourneyPathProps {\n steps: JourneyStep[];\n /** The signed-in user's `rewards.breakdown` — a step is done when its\n * actionType key is present with a positive value. Pass `{}` (or omit)\n * for a signed-out visitor — every step renders upcoming. */\n breakdown?: Record<string, number>;\n className?: string;\n}\n\ntype StepState = \"done\" | \"current\" | \"upcoming\";\n\nfunction stateFor(step: JourneyStep, index: number, steps: JourneyStep[], breakdown: Record<string, number>): StepState {\n if ((breakdown[step.actionType] ?? 0) > 0) return \"done\";\n const firstNotDone = steps.findIndex((s) => (breakdown[s.actionType] ?? 0) <= 0);\n return index === firstNotDone ? \"current\" : \"upcoming\";\n}\n\n/** A permanent, ordered milestone path — no time window, no reset, no\n * comparison to other users. A step lights up the moment its action has\n * ever been done and stays lit forever; the first not-yet-done step is\n * highlighted as \"current\". Safe to render for a signed-out visitor\n * (`breakdown` omitted) — every step just renders upcoming, still linkable. */\nexport function JourneyPath({ steps, breakdown = {}, className }: JourneyPathProps) {\n return (\n <ol className={cn(\"flex flex-col gap-1\", className)}>\n {steps.map((step, i) => {\n const state = stateFor(step, i, steps, breakdown);\n const Icon = step.icon;\n return (\n <li key={step.actionType} className=\"relative flex items-center gap-3\">\n {i < steps.length - 1 && (\n <span\n aria-hidden\n className={cn(\n \"absolute left-[15px] top-8 h-[calc(100%-8px)] w-px\",\n state === \"done\" ? \"bg-brand-rose/50\" : \"bg-border\"\n )}\n />\n )}\n <a\n href={step.href}\n className={cn(\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border transition-colors\",\n state === \"done\" && \"border-brand-rose/40 bg-brand-rose/15 text-brand-rose\",\n state === \"current\" && \"border-brand-orange/60 bg-brand-orange/10 text-brand-orange\",\n state === \"upcoming\" && \"border-border text-muted-foreground/50\"\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n </a>\n <a\n href={step.href}\n className={cn(\n \"flex-1 rounded-lg py-1.5 text-sm font-semibold transition-colors hover:text-foreground\",\n state === \"upcoming\" ? \"text-muted-foreground/60\" : \"text-foreground\"\n )}\n >\n {step.label}\n </a>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwCU;AAvCV,gBAAmB;AAqBnB,SAAS,SAAS,MAAmB,OAAe,OAAsB,WAA8C;AACtH,OAAK,UAAU,KAAK,UAAU,KAAK,KAAK,EAAG,QAAO;AAClD,QAAM,eAAe,MAAM,UAAU,CAAC,OAAO,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC;AAC/E,SAAO,UAAU,eAAe,YAAY;AAC9C;AAOO,SAAS,YAAY,EAAE,OAAO,YAAY,CAAC,GAAG,UAAU,GAAqB;AAClF,SACE,4CAAC,QAAG,eAAW,cAAG,uBAAuB,SAAS,GAC/C,gBAAM,IAAI,CAAC,MAAM,MAAM;AACtB,UAAM,QAAQ,SAAS,MAAM,GAAG,OAAO,SAAS;AAChD,UAAM,OAAO,KAAK;AAClB,WACE,6CAAC,QAAyB,WAAU,oCACjC;AAAA,UAAI,MAAM,SAAS,KAClB;AAAA,QAAC;AAAA;AAAA,UACC,eAAW;AAAA,UACX,eAAW;AAAA,YACT;AAAA,YACA,UAAU,SAAS,qBAAqB;AAAA,UAC1C;AAAA;AAAA,MACF;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,eAAW;AAAA,YACT;AAAA,YACA,UAAU,UAAU;AAAA,YACpB,UAAU,aAAa;AAAA,YACvB,UAAU,cAAc;AAAA,UAC1B;AAAA,UAEA,sDAAC,QAAK,WAAU,eAAc;AAAA;AAAA,MAChC;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,eAAW;AAAA,YACT;AAAA,YACA,UAAU,aAAa,6BAA6B;AAAA,UACtD;AAAA,UAEC,eAAK;AAAA;AAAA,MACR;AAAA,SA7BO,KAAK,UA8Bd;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
@@ -0,0 +1,26 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ElementType } from 'react';
3
+
4
+ interface JourneyStep {
5
+ /** Matches a key in the rewards breakdown (e.g. "mint_asset"). */
6
+ actionType: string;
7
+ label: string;
8
+ href: string;
9
+ icon: ElementType;
10
+ }
11
+ interface JourneyPathProps {
12
+ steps: JourneyStep[];
13
+ /** The signed-in user's `rewards.breakdown` — a step is done when its
14
+ * actionType key is present with a positive value. Pass `{}` (or omit)
15
+ * for a signed-out visitor — every step renders upcoming. */
16
+ breakdown?: Record<string, number>;
17
+ className?: string;
18
+ }
19
+ /** A permanent, ordered milestone path — no time window, no reset, no
20
+ * comparison to other users. A step lights up the moment its action has
21
+ * ever been done and stays lit forever; the first not-yet-done step is
22
+ * highlighted as "current". Safe to render for a signed-out visitor
23
+ * (`breakdown` omitted) — every step just renders upcoming, still linkable. */
24
+ declare function JourneyPath({ steps, breakdown, className }: JourneyPathProps): react_jsx_runtime.JSX.Element;
25
+
26
+ export { JourneyPath, type JourneyPathProps, type JourneyStep };
@@ -0,0 +1,26 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ElementType } from 'react';
3
+
4
+ interface JourneyStep {
5
+ /** Matches a key in the rewards breakdown (e.g. "mint_asset"). */
6
+ actionType: string;
7
+ label: string;
8
+ href: string;
9
+ icon: ElementType;
10
+ }
11
+ interface JourneyPathProps {
12
+ steps: JourneyStep[];
13
+ /** The signed-in user's `rewards.breakdown` — a step is done when its
14
+ * actionType key is present with a positive value. Pass `{}` (or omit)
15
+ * for a signed-out visitor — every step renders upcoming. */
16
+ breakdown?: Record<string, number>;
17
+ className?: string;
18
+ }
19
+ /** A permanent, ordered milestone path — no time window, no reset, no
20
+ * comparison to other users. A step lights up the moment its action has
21
+ * ever been done and stays lit forever; the first not-yet-done step is
22
+ * highlighted as "current". Safe to render for a signed-out visitor
23
+ * (`breakdown` omitted) — every step just renders upcoming, still linkable. */
24
+ declare function JourneyPath({ steps, breakdown, className }: JourneyPathProps): react_jsx_runtime.JSX.Element;
25
+
26
+ export { JourneyPath, type JourneyPathProps, type JourneyStep };
@@ -0,0 +1,53 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../utils/cn.js";
3
+ function stateFor(step, index, steps, breakdown) {
4
+ if ((breakdown[step.actionType] ?? 0) > 0) return "done";
5
+ const firstNotDone = steps.findIndex((s) => (breakdown[s.actionType] ?? 0) <= 0);
6
+ return index === firstNotDone ? "current" : "upcoming";
7
+ }
8
+ function JourneyPath({ steps, breakdown = {}, className }) {
9
+ return /* @__PURE__ */ jsx("ol", { className: cn("flex flex-col gap-1", className), children: steps.map((step, i) => {
10
+ const state = stateFor(step, i, steps, breakdown);
11
+ const Icon = step.icon;
12
+ return /* @__PURE__ */ jsxs("li", { className: "relative flex items-center gap-3", children: [
13
+ i < steps.length - 1 && /* @__PURE__ */ jsx(
14
+ "span",
15
+ {
16
+ "aria-hidden": true,
17
+ className: cn(
18
+ "absolute left-[15px] top-8 h-[calc(100%-8px)] w-px",
19
+ state === "done" ? "bg-brand-rose/50" : "bg-border"
20
+ )
21
+ }
22
+ ),
23
+ /* @__PURE__ */ jsx(
24
+ "a",
25
+ {
26
+ href: step.href,
27
+ className: cn(
28
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-full border transition-colors",
29
+ state === "done" && "border-brand-rose/40 bg-brand-rose/15 text-brand-rose",
30
+ state === "current" && "border-brand-orange/60 bg-brand-orange/10 text-brand-orange",
31
+ state === "upcoming" && "border-border text-muted-foreground/50"
32
+ ),
33
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" })
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsx(
37
+ "a",
38
+ {
39
+ href: step.href,
40
+ className: cn(
41
+ "flex-1 rounded-lg py-1.5 text-sm font-semibold transition-colors hover:text-foreground",
42
+ state === "upcoming" ? "text-muted-foreground/60" : "text-foreground"
43
+ ),
44
+ children: step.label
45
+ }
46
+ )
47
+ ] }, step.actionType);
48
+ }) });
49
+ }
50
+ export {
51
+ JourneyPath
52
+ };
53
+ //# sourceMappingURL=journey-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/journey-path.tsx"],"sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface JourneyStep {\n /** Matches a key in the rewards breakdown (e.g. \"mint_asset\"). */\n actionType: string;\n label: string;\n href: string;\n icon: ElementType;\n}\n\nexport interface JourneyPathProps {\n steps: JourneyStep[];\n /** The signed-in user's `rewards.breakdown` — a step is done when its\n * actionType key is present with a positive value. Pass `{}` (or omit)\n * for a signed-out visitor — every step renders upcoming. */\n breakdown?: Record<string, number>;\n className?: string;\n}\n\ntype StepState = \"done\" | \"current\" | \"upcoming\";\n\nfunction stateFor(step: JourneyStep, index: number, steps: JourneyStep[], breakdown: Record<string, number>): StepState {\n if ((breakdown[step.actionType] ?? 0) > 0) return \"done\";\n const firstNotDone = steps.findIndex((s) => (breakdown[s.actionType] ?? 0) <= 0);\n return index === firstNotDone ? \"current\" : \"upcoming\";\n}\n\n/** A permanent, ordered milestone path — no time window, no reset, no\n * comparison to other users. A step lights up the moment its action has\n * ever been done and stays lit forever; the first not-yet-done step is\n * highlighted as \"current\". Safe to render for a signed-out visitor\n * (`breakdown` omitted) — every step just renders upcoming, still linkable. */\nexport function JourneyPath({ steps, breakdown = {}, className }: JourneyPathProps) {\n return (\n <ol className={cn(\"flex flex-col gap-1\", className)}>\n {steps.map((step, i) => {\n const state = stateFor(step, i, steps, breakdown);\n const Icon = step.icon;\n return (\n <li key={step.actionType} className=\"relative flex items-center gap-3\">\n {i < steps.length - 1 && (\n <span\n aria-hidden\n className={cn(\n \"absolute left-[15px] top-8 h-[calc(100%-8px)] w-px\",\n state === \"done\" ? \"bg-brand-rose/50\" : \"bg-border\"\n )}\n />\n )}\n <a\n href={step.href}\n className={cn(\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border transition-colors\",\n state === \"done\" && \"border-brand-rose/40 bg-brand-rose/15 text-brand-rose\",\n state === \"current\" && \"border-brand-orange/60 bg-brand-orange/10 text-brand-orange\",\n state === \"upcoming\" && \"border-border text-muted-foreground/50\"\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n </a>\n <a\n href={step.href}\n className={cn(\n \"flex-1 rounded-lg py-1.5 text-sm font-semibold transition-colors hover:text-foreground\",\n state === \"upcoming\" ? \"text-muted-foreground/60\" : \"text-foreground\"\n )}\n >\n {step.label}\n </a>\n </li>\n );\n })}\n </ol>\n );\n}\n"],"mappings":"AAwCU,SAEI,KAFJ;AAvCV,SAAS,UAAU;AAqBnB,SAAS,SAAS,MAAmB,OAAe,OAAsB,WAA8C;AACtH,OAAK,UAAU,KAAK,UAAU,KAAK,KAAK,EAAG,QAAO;AAClD,QAAM,eAAe,MAAM,UAAU,CAAC,OAAO,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC;AAC/E,SAAO,UAAU,eAAe,YAAY;AAC9C;AAOO,SAAS,YAAY,EAAE,OAAO,YAAY,CAAC,GAAG,UAAU,GAAqB;AAClF,SACE,oBAAC,QAAG,WAAW,GAAG,uBAAuB,SAAS,GAC/C,gBAAM,IAAI,CAAC,MAAM,MAAM;AACtB,UAAM,QAAQ,SAAS,MAAM,GAAG,OAAO,SAAS;AAChD,UAAM,OAAO,KAAK;AAClB,WACE,qBAAC,QAAyB,WAAU,oCACjC;AAAA,UAAI,MAAM,SAAS,KAClB;AAAA,QAAC;AAAA;AAAA,UACC,eAAW;AAAA,UACX,WAAW;AAAA,YACT;AAAA,YACA,UAAU,SAAS,qBAAqB;AAAA,UAC1C;AAAA;AAAA,MACF;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,WAAW;AAAA,YACT;AAAA,YACA,UAAU,UAAU;AAAA,YACpB,UAAU,aAAa;AAAA,YACvB,UAAU,cAAc;AAAA,UAC1B;AAAA,UAEA,8BAAC,QAAK,WAAU,eAAc;AAAA;AAAA,MAChC;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,WAAW;AAAA,YACT;AAAA,YACA,UAAU,aAAa,6BAA6B;AAAA,UACtD;AAAA,UAEC,eAAK;AAAA;AAAA,MACR;AAAA,SA7BO,KAAK,UA8Bd;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
@@ -44,7 +44,7 @@ function LeaderboardTable({ entries, highlightAddress, renderAddress, className
44
44
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_level_badge.LevelBadge, { level: e.currentLevel, name: e.currentLevelName, badgeColor: e.badgeColor, size: "sm", className: "hidden sm:inline-flex" }),
45
45
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "shrink-0 text-sm font-semibold tabular-nums", children: [
46
46
  e.totalXp.toLocaleString(),
47
- " pts"
47
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-1 text-xs font-normal text-muted-foreground", children: "XP" })
48
48
  ] })
49
49
  ]
50
50
  },