@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.
- package/dist/components/community-rewards-section.cjs +12 -9
- package/dist/components/community-rewards-section.cjs.map +1 -1
- package/dist/components/community-rewards-section.js +12 -9
- package/dist/components/community-rewards-section.js.map +1 -1
- package/dist/components/rewards/badge-shelf.cjs +2 -0
- package/dist/components/rewards/badge-shelf.cjs.map +1 -1
- package/dist/components/rewards/badge-shelf.d.cts +6 -1
- package/dist/components/rewards/badge-shelf.d.ts +6 -1
- package/dist/components/rewards/badge-shelf.js +1 -0
- package/dist/components/rewards/badge-shelf.js.map +1 -1
- package/dist/components/rewards/badge-unlock-toast-content.cjs +49 -0
- package/dist/components/rewards/badge-unlock-toast-content.cjs.map +1 -0
- package/dist/components/rewards/badge-unlock-toast-content.d.cts +11 -0
- package/dist/components/rewards/badge-unlock-toast-content.d.ts +11 -0
- package/dist/components/rewards/badge-unlock-toast-content.js +25 -0
- package/dist/components/rewards/badge-unlock-toast-content.js.map +1 -0
- package/dist/components/rewards/journey-path.cjs +77 -0
- package/dist/components/rewards/journey-path.cjs.map +1 -0
- package/dist/components/rewards/journey-path.d.cts +26 -0
- package/dist/components/rewards/journey-path.d.ts +26 -0
- package/dist/components/rewards/journey-path.js +53 -0
- package/dist/components/rewards/journey-path.js.map +1 -0
- package/dist/components/rewards/leaderboard-table.cjs +1 -1
- package/dist/components/rewards/leaderboard-table.cjs.map +1 -1
- package/dist/components/rewards/leaderboard-table.js +1 -1
- package/dist/components/rewards/leaderboard-table.js.map +1 -1
- package/dist/components/rewards/level-badge.cjs +1 -3
- package/dist/components/rewards/level-badge.cjs.map +1 -1
- package/dist/components/rewards/level-badge.d.cts +4 -2
- package/dist/components/rewards/level-badge.d.ts +4 -2
- package/dist/components/rewards/level-badge.js +1 -3
- package/dist/components/rewards/level-badge.js.map +1 -1
- package/dist/components/rewards/level-up-celebration.cjs +71 -0
- package/dist/components/rewards/level-up-celebration.cjs.map +1 -0
- package/dist/components/rewards/level-up-celebration.d.cts +16 -0
- package/dist/components/rewards/level-up-celebration.d.ts +16 -0
- package/dist/components/rewards/level-up-celebration.js +47 -0
- package/dist/components/rewards/level-up-celebration.js.map +1 -0
- package/dist/components/rewards/reward-toast.cjs +20 -2
- package/dist/components/rewards/reward-toast.cjs.map +1 -1
- package/dist/components/rewards/reward-toast.d.cts +6 -2
- package/dist/components/rewards/reward-toast.d.ts +6 -2
- package/dist/components/rewards/reward-toast.js +20 -2
- package/dist/components/rewards/reward-toast.js.map +1 -1
- package/dist/components/rewards/use-rewards-celebrations.cjs +70 -0
- package/dist/components/rewards/use-rewards-celebrations.cjs.map +1 -0
- package/dist/components/rewards/use-rewards-celebrations.d.cts +25 -0
- package/dist/components/rewards/use-rewards-celebrations.d.ts +25 -0
- package/dist/components/rewards/use-rewards-celebrations.js +46 -0
- package/dist/components/rewards/use-rewards-celebrations.js.map +1 -0
- package/dist/components/rewards/xp-toast-content.cjs +23 -18
- package/dist/components/rewards/xp-toast-content.cjs.map +1 -1
- package/dist/components/rewards/xp-toast-content.d.cts +7 -1
- package/dist/components/rewards/xp-toast-content.d.ts +7 -1
- package/dist/components/rewards/xp-toast-content.js +23 -18
- package/dist/components/rewards/xp-toast-content.js.map +1 -1
- package/dist/index.cjs +14 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- 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.
|
|
64
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
65
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
66
|
-
|
|
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\
|
|
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'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's Fund.\n </p>\n </div>\n\n {/* Recently active — live 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__ */
|
|
31
|
-
/* @__PURE__ */ jsx("
|
|
32
|
-
/* @__PURE__ */ jsx("
|
|
33
|
-
|
|
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\
|
|
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'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's Fund.\n </p>\n </div>\n\n {/* Recently active — live 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\
|
|
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 };
|
|
@@ -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\
|
|
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
|
-
"
|
|
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
|
},
|