@medialane/ui 0.97.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/components/community-rewards-section.cjs +123 -0
  2. package/dist/components/community-rewards-section.cjs.map +1 -0
  3. package/dist/components/community-rewards-section.d.cts +15 -0
  4. package/dist/components/community-rewards-section.d.ts +15 -0
  5. package/dist/components/community-rewards-section.js +89 -0
  6. package/dist/components/community-rewards-section.js.map +1 -0
  7. package/dist/components/creator-airdrop-banner.cjs +79 -0
  8. package/dist/components/creator-airdrop-banner.cjs.map +1 -0
  9. package/dist/components/creator-airdrop-banner.d.cts +9 -0
  10. package/dist/components/creator-airdrop-banner.d.ts +9 -0
  11. package/dist/components/creator-airdrop-banner.js +45 -0
  12. package/dist/components/creator-airdrop-banner.js.map +1 -0
  13. package/dist/components/rewards/badge-shelf.cjs +2 -0
  14. package/dist/components/rewards/badge-shelf.cjs.map +1 -1
  15. package/dist/components/rewards/badge-shelf.d.cts +6 -1
  16. package/dist/components/rewards/badge-shelf.d.ts +6 -1
  17. package/dist/components/rewards/badge-shelf.js +1 -0
  18. package/dist/components/rewards/badge-shelf.js.map +1 -1
  19. package/dist/components/rewards/badge-unlock-toast-content.cjs +49 -0
  20. package/dist/components/rewards/badge-unlock-toast-content.cjs.map +1 -0
  21. package/dist/components/rewards/badge-unlock-toast-content.d.cts +11 -0
  22. package/dist/components/rewards/badge-unlock-toast-content.d.ts +11 -0
  23. package/dist/components/rewards/badge-unlock-toast-content.js +25 -0
  24. package/dist/components/rewards/badge-unlock-toast-content.js.map +1 -0
  25. package/dist/components/rewards/journey-path.cjs +77 -0
  26. package/dist/components/rewards/journey-path.cjs.map +1 -0
  27. package/dist/components/rewards/journey-path.d.cts +26 -0
  28. package/dist/components/rewards/journey-path.d.ts +26 -0
  29. package/dist/components/rewards/journey-path.js +53 -0
  30. package/dist/components/rewards/journey-path.js.map +1 -0
  31. package/dist/components/rewards/level-badge.cjs +1 -3
  32. package/dist/components/rewards/level-badge.cjs.map +1 -1
  33. package/dist/components/rewards/level-badge.d.cts +4 -2
  34. package/dist/components/rewards/level-badge.d.ts +4 -2
  35. package/dist/components/rewards/level-badge.js +1 -3
  36. package/dist/components/rewards/level-badge.js.map +1 -1
  37. package/dist/components/rewards/level-up-celebration.cjs +71 -0
  38. package/dist/components/rewards/level-up-celebration.cjs.map +1 -0
  39. package/dist/components/rewards/level-up-celebration.d.cts +16 -0
  40. package/dist/components/rewards/level-up-celebration.d.ts +16 -0
  41. package/dist/components/rewards/level-up-celebration.js +47 -0
  42. package/dist/components/rewards/level-up-celebration.js.map +1 -0
  43. package/dist/components/rewards/reward-toast.cjs +20 -2
  44. package/dist/components/rewards/reward-toast.cjs.map +1 -1
  45. package/dist/components/rewards/reward-toast.d.cts +6 -2
  46. package/dist/components/rewards/reward-toast.d.ts +6 -2
  47. package/dist/components/rewards/reward-toast.js +20 -2
  48. package/dist/components/rewards/reward-toast.js.map +1 -1
  49. package/dist/components/rewards/use-rewards-celebrations.cjs +70 -0
  50. package/dist/components/rewards/use-rewards-celebrations.cjs.map +1 -0
  51. package/dist/components/rewards/use-rewards-celebrations.d.cts +25 -0
  52. package/dist/components/rewards/use-rewards-celebrations.d.ts +25 -0
  53. package/dist/components/rewards/use-rewards-celebrations.js +46 -0
  54. package/dist/components/rewards/use-rewards-celebrations.js.map +1 -0
  55. package/dist/components/rewards/xp-toast-content.cjs +23 -18
  56. package/dist/components/rewards/xp-toast-content.cjs.map +1 -1
  57. package/dist/components/rewards/xp-toast-content.d.cts +7 -1
  58. package/dist/components/rewards/xp-toast-content.d.ts +7 -1
  59. package/dist/components/rewards/xp-toast-content.js +23 -18
  60. package/dist/components/rewards/xp-toast-content.js.map +1 -1
  61. package/dist/index.cjs +20 -5
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +7 -2
  64. package/dist/index.d.ts +7 -2
  65. package/dist/index.js +13 -3
  66. package/dist/index.js.map +1 -1
  67. package/package.json +1 -1
  68. package/dist/components/creators-fund-section.cjs +0 -139
  69. package/dist/components/creators-fund-section.cjs.map +0 -1
  70. package/dist/components/creators-fund-section.d.cts +0 -26
  71. package/dist/components/creators-fund-section.d.ts +0 -26
  72. package/dist/components/creators-fund-section.js +0 -105
  73. package/dist/components/creators-fund-section.js.map +0 -1
@@ -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":[]}
@@ -37,6 +37,7 @@ function LevelBadge({ level, name, badgeColor, size = "md", className }) {
37
37
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
38
38
  "span",
39
39
  {
40
+ title: `Level ${level}`,
40
41
  className: (0, import_cn.cn)(
41
42
  "inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap",
42
43
  sizeClasses[size],
@@ -45,9 +46,6 @@ function LevelBadge({ level, name, badgeColor, size = "md", className }) {
45
46
  style: { borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor },
46
47
  children: [
47
48
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("rounded-full shrink-0", dotSizes[size]), style: { backgroundColor: badgeColor } }),
48
- "Lv.",
49
- level,
50
- " ",
51
49
  name
52
50
  ]
53
51
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/rewards/level-badge.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelBadgeProps {\n level: number;\n name: string;\n badgeColor: string;\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n}\n\n/** Color-coded level chip (\"Lv.6 Voyager\"). Pure presentation — the consuming\n * app supplies level data from the rewards API. */\nexport function LevelBadge({ level, name, badgeColor, size = \"md\", className }: LevelBadgeProps) {\n const sizeClasses = {\n sm: \"h-5 px-1.5 gap-1 text-[10px]\",\n md: \"h-6 px-2 gap-1.5 text-xs\",\n lg: \"h-8 px-3 gap-2 text-sm\",\n };\n\n const dotSizes = {\n sm: \"h-1.5 w-1.5\",\n md: \"h-2 w-2\",\n lg: \"h-2.5 w-2.5\",\n };\n\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap\",\n sizeClasses[size],\n className\n )}\n style={{ borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor }}\n >\n <span className={cn(\"rounded-full shrink-0\", dotSizes[size])} style={{ backgroundColor: badgeColor }} />\n Lv.{level} {name}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BI;AA1BJ,gBAAmB;AAYZ,SAAS,WAAW,EAAE,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,GAAoB;AAC/F,QAAM,cAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,QAAM,WAAW;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,QACT;AAAA,QACA,YAAY,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,MACA,OAAO,EAAE,aAAa,GAAG,UAAU,MAAM,iBAAiB,GAAG,UAAU,MAAM,OAAO,WAAW;AAAA,MAE/F;AAAA,oDAAC,UAAK,eAAW,cAAG,yBAAyB,SAAS,IAAI,CAAC,GAAG,OAAO,EAAE,iBAAiB,WAAW,GAAG;AAAA,QAAE;AAAA,QACpG;AAAA,QAAM;AAAA,QAAE;AAAA;AAAA;AAAA,EACd;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/rewards/level-badge.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelBadgeProps {\n level: number;\n name: string;\n badgeColor: string;\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n}\n\n/** Color-coded level chip — shows the level's title only (\"Voyager\"), not\n * the raw number (\"Lv.6 Voyager\" read as UI noise). The level is still\n * available on hover via the native title tooltip. Pure presentation — the\n * consuming app supplies level data from the rewards API. */\nexport function LevelBadge({ level, name, badgeColor, size = \"md\", className }: LevelBadgeProps) {\n const sizeClasses = {\n sm: \"h-5 px-1.5 gap-1 text-[10px]\",\n md: \"h-6 px-2 gap-1.5 text-xs\",\n lg: \"h-8 px-3 gap-2 text-sm\",\n };\n\n const dotSizes = {\n sm: \"h-1.5 w-1.5\",\n md: \"h-2 w-2\",\n lg: \"h-2.5 w-2.5\",\n };\n\n return (\n <span\n title={`Level ${level}`}\n className={cn(\n \"inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap\",\n sizeClasses[size],\n className\n )}\n style={{ borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor }}\n >\n <span className={cn(\"rounded-full shrink-0\", dotSizes[size])} style={{ backgroundColor: badgeColor }} />\n {name}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BI;AA5BJ,gBAAmB;AAcZ,SAAS,WAAW,EAAE,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,GAAoB;AAC/F,QAAM,cAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,QAAM,WAAW;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,SAAS,KAAK;AAAA,MACrB,eAAW;AAAA,QACT;AAAA,QACA,YAAY,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,MACA,OAAO,EAAE,aAAa,GAAG,UAAU,MAAM,iBAAiB,GAAG,UAAU,MAAM,OAAO,WAAW;AAAA,MAE/F;AAAA,oDAAC,UAAK,eAAW,cAAG,yBAAyB,SAAS,IAAI,CAAC,GAAG,OAAO,EAAE,iBAAiB,WAAW,GAAG;AAAA,QACrG;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -7,8 +7,10 @@ interface LevelBadgeProps {
7
7
  size?: "sm" | "md" | "lg";
8
8
  className?: string;
9
9
  }
10
- /** Color-coded level chip ("Lv.6 Voyager"). Pure presentation — the consuming
11
- * app supplies level data from the rewards API. */
10
+ /** Color-coded level chip — shows the level's title only ("Voyager"), not
11
+ * the raw number ("Lv.6 Voyager" read as UI noise). The level is still
12
+ * available on hover via the native title tooltip. Pure presentation — the
13
+ * consuming app supplies level data from the rewards API. */
12
14
  declare function LevelBadge({ level, name, badgeColor, size, className }: LevelBadgeProps): react_jsx_runtime.JSX.Element;
13
15
 
14
16
  export { LevelBadge, type LevelBadgeProps };
@@ -7,8 +7,10 @@ interface LevelBadgeProps {
7
7
  size?: "sm" | "md" | "lg";
8
8
  className?: string;
9
9
  }
10
- /** Color-coded level chip ("Lv.6 Voyager"). Pure presentation — the consuming
11
- * app supplies level data from the rewards API. */
10
+ /** Color-coded level chip — shows the level's title only ("Voyager"), not
11
+ * the raw number ("Lv.6 Voyager" read as UI noise). The level is still
12
+ * available on hover via the native title tooltip. Pure presentation — the
13
+ * consuming app supplies level data from the rewards API. */
12
14
  declare function LevelBadge({ level, name, badgeColor, size, className }: LevelBadgeProps): react_jsx_runtime.JSX.Element;
13
15
 
14
16
  export { LevelBadge, type LevelBadgeProps };
@@ -14,6 +14,7 @@ function LevelBadge({ level, name, badgeColor, size = "md", className }) {
14
14
  return /* @__PURE__ */ jsxs(
15
15
  "span",
16
16
  {
17
+ title: `Level ${level}`,
17
18
  className: cn(
18
19
  "inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap",
19
20
  sizeClasses[size],
@@ -22,9 +23,6 @@ function LevelBadge({ level, name, badgeColor, size = "md", className }) {
22
23
  style: { borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor },
23
24
  children: [
24
25
  /* @__PURE__ */ jsx("span", { className: cn("rounded-full shrink-0", dotSizes[size]), style: { backgroundColor: badgeColor } }),
25
- "Lv.",
26
- level,
27
- " ",
28
26
  name
29
27
  ]
30
28
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/rewards/level-badge.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelBadgeProps {\n level: number;\n name: string;\n badgeColor: string;\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n}\n\n/** Color-coded level chip (\"Lv.6 Voyager\"). Pure presentation — the consuming\n * app supplies level data from the rewards API. */\nexport function LevelBadge({ level, name, badgeColor, size = \"md\", className }: LevelBadgeProps) {\n const sizeClasses = {\n sm: \"h-5 px-1.5 gap-1 text-[10px]\",\n md: \"h-6 px-2 gap-1.5 text-xs\",\n lg: \"h-8 px-3 gap-2 text-sm\",\n };\n\n const dotSizes = {\n sm: \"h-1.5 w-1.5\",\n md: \"h-2 w-2\",\n lg: \"h-2.5 w-2.5\",\n };\n\n return (\n <span\n className={cn(\n \"inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap\",\n sizeClasses[size],\n className\n )}\n style={{ borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor }}\n >\n <span className={cn(\"rounded-full shrink-0\", dotSizes[size])} style={{ backgroundColor: badgeColor }} />\n Lv.{level} {name}\n </span>\n );\n}\n"],"mappings":"AA0BI,SAQE,KARF;AA1BJ,SAAS,UAAU;AAYZ,SAAS,WAAW,EAAE,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,GAAoB;AAC/F,QAAM,cAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,QAAM,WAAW;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,YAAY,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,MACA,OAAO,EAAE,aAAa,GAAG,UAAU,MAAM,iBAAiB,GAAG,UAAU,MAAM,OAAO,WAAW;AAAA,MAE/F;AAAA,4BAAC,UAAK,WAAW,GAAG,yBAAyB,SAAS,IAAI,CAAC,GAAG,OAAO,EAAE,iBAAiB,WAAW,GAAG;AAAA,QAAE;AAAA,QACpG;AAAA,QAAM;AAAA,QAAE;AAAA;AAAA;AAAA,EACd;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/rewards/level-badge.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelBadgeProps {\n level: number;\n name: string;\n badgeColor: string;\n size?: \"sm\" | \"md\" | \"lg\";\n className?: string;\n}\n\n/** Color-coded level chip — shows the level's title only (\"Voyager\"), not\n * the raw number (\"Lv.6 Voyager\" read as UI noise). The level is still\n * available on hover via the native title tooltip. Pure presentation — the\n * consuming app supplies level data from the rewards API. */\nexport function LevelBadge({ level, name, badgeColor, size = \"md\", className }: LevelBadgeProps) {\n const sizeClasses = {\n sm: \"h-5 px-1.5 gap-1 text-[10px]\",\n md: \"h-6 px-2 gap-1.5 text-xs\",\n lg: \"h-8 px-3 gap-2 text-sm\",\n };\n\n const dotSizes = {\n sm: \"h-1.5 w-1.5\",\n md: \"h-2 w-2\",\n lg: \"h-2.5 w-2.5\",\n };\n\n return (\n <span\n title={`Level ${level}`}\n className={cn(\n \"inline-flex items-center rounded-full border font-semibold tracking-tight whitespace-nowrap\",\n sizeClasses[size],\n className\n )}\n style={{ borderColor: `${badgeColor}60`, backgroundColor: `${badgeColor}18`, color: badgeColor }}\n >\n <span className={cn(\"rounded-full shrink-0\", dotSizes[size])} style={{ backgroundColor: badgeColor }} />\n {name}\n </span>\n );\n}\n"],"mappings":"AA4BI,SASE,KATF;AA5BJ,SAAS,UAAU;AAcZ,SAAS,WAAW,EAAE,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,GAAoB;AAC/F,QAAM,cAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,QAAM,WAAW;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,SAAS,KAAK;AAAA,MACrB,WAAW;AAAA,QACT;AAAA,QACA,YAAY,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,MACA,OAAO,EAAE,aAAa,GAAG,UAAU,MAAM,iBAAiB,GAAG,UAAU,MAAM,OAAO,WAAW;AAAA,MAE/F;AAAA,4BAAC,UAAK,WAAW,GAAG,yBAAyB,SAAS,IAAI,CAAC,GAAG,OAAO,EAAE,iBAAiB,WAAW,GAAG;AAAA,QACrG;AAAA;AAAA;AAAA,EACH;AAEJ;","names":[]}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var level_up_celebration_exports = {};
21
+ __export(level_up_celebration_exports, {
22
+ LevelUpCelebration: () => LevelUpCelebration
23
+ });
24
+ module.exports = __toCommonJS(level_up_celebration_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_react = require("react");
27
+ var import_level_badge = require("./level-badge.js");
28
+ var import_cn = require("../../utils/cn.js");
29
+ const PARTICLE_COUNT = 14;
30
+ function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }) {
31
+ (0, import_react.useEffect)(() => {
32
+ const timer = setTimeout(onDismiss, 3e3);
33
+ return () => clearTimeout(timer);
34
+ }, [onDismiss]);
35
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
36
+ "div",
37
+ {
38
+ role: "status",
39
+ "aria-live": "polite",
40
+ className: (0, import_cn.cn)(
41
+ "fixed inset-0 z-[200] flex items-center justify-center bg-background/40 backdrop-blur-sm",
42
+ className
43
+ ),
44
+ onClick: onDismiss,
45
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative flex flex-col items-center gap-3 animate-in zoom-in-95 fade-in duration-300", children: [
46
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pointer-events-none absolute inset-0 -z-10", children: Array.from({ length: PARTICLE_COUNT }).map((_, i) => {
47
+ const angle = 360 / PARTICLE_COUNT * i;
48
+ const distance = 60 + i % 3 * 20;
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
50
+ "span",
51
+ {
52
+ className: "absolute left-1/2 top-1/2 h-1.5 w-1.5 rounded-full animate-in fade-in zoom-in duration-700",
53
+ style: {
54
+ backgroundColor: badgeColor,
55
+ transform: `rotate(${angle}deg) translate(${distance}px) rotate(-${angle}deg)`
56
+ }
57
+ },
58
+ i
59
+ );
60
+ }) }),
61
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-bold uppercase tracking-widest text-muted-foreground", children: "Level up" }),
62
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_level_badge.LevelBadge, { level, name, badgeColor, size: "lg" })
63
+ ] })
64
+ }
65
+ );
66
+ }
67
+ // Annotate the CommonJS export names for ESM import in node:
68
+ 0 && (module.exports = {
69
+ LevelUpCelebration
70
+ });
71
+ //# sourceMappingURL=level-up-celebration.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/level-up-celebration.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { LevelBadge } from \"./level-badge.js\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface LevelUpCelebrationProps {\n level: number;\n name: string;\n badgeColor: string;\n onDismiss: () => void;\n className?: string;\n}\n\nconst PARTICLE_COUNT = 14;\n\n/** Auto-dismissing celebration burst for a level-up moment. Pure CSS\n * animation, no dependency — particles are positioned/rotated via inline\n * style so the same component works without a keyframe-per-particle\n * stylesheet entry. */\nexport function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }: LevelUpCelebrationProps) {\n useEffect(() => {\n const timer = setTimeout(onDismiss, 3000);\n return () => clearTimeout(timer);\n }, [onDismiss]);\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"fixed inset-0 z-[200] flex items-center justify-center bg-background/40 backdrop-blur-sm\",\n className\n )}\n onClick={onDismiss}\n >\n <div className=\"relative flex flex-col items-center gap-3 animate-in zoom-in-95 fade-in duration-300\">\n <div className=\"pointer-events-none absolute inset-0 -z-10\">\n {Array.from({ length: PARTICLE_COUNT }).map((_, i) => {\n const angle = (360 / PARTICLE_COUNT) * i;\n const distance = 60 + (i % 3) * 20;\n return (\n <span\n key={i}\n className=\"absolute left-1/2 top-1/2 h-1.5 w-1.5 rounded-full animate-in fade-in zoom-in duration-700\"\n style={{\n backgroundColor: badgeColor,\n transform: `rotate(${angle}deg) translate(${distance}px) rotate(-${angle}deg)`,\n }}\n />\n );\n })}\n </div>\n <p className=\"text-sm font-bold uppercase tracking-widest text-muted-foreground\">Level up</p>\n <LevelBadge level={level} name={name} badgeColor={badgeColor} size=\"lg\" />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCM;AAlCN,mBAA0B;AAC1B,yBAA2B;AAC3B,gBAAmB;AAUnB,MAAM,iBAAiB;AAMhB,SAAS,mBAAmB,EAAE,OAAO,MAAM,YAAY,WAAW,UAAU,GAA4B;AAC7G,8BAAU,MAAM;AACd,UAAM,QAAQ,WAAW,WAAW,GAAI;AACxC,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,SAAS,CAAC;AAEd,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,eAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS;AAAA,MAET,uDAAC,SAAI,WAAU,wFACb;AAAA,oDAAC,SAAI,WAAU,8CACZ,gBAAM,KAAK,EAAE,QAAQ,eAAe,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM;AACpD,gBAAM,QAAS,MAAM,iBAAkB;AACvC,gBAAM,WAAW,KAAM,IAAI,IAAK;AAChC,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,iBAAiB;AAAA,gBACjB,WAAW,UAAU,KAAK,kBAAkB,QAAQ,eAAe,KAAK;AAAA,cAC1E;AAAA;AAAA,YALK;AAAA,UAMP;AAAA,QAEJ,CAAC,GACH;AAAA,QACA,4CAAC,OAAE,WAAU,qEAAoE,sBAAQ;AAAA,QACzF,4CAAC,iCAAW,OAAc,MAAY,YAAwB,MAAK,MAAK;AAAA,SAC1E;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,16 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface LevelUpCelebrationProps {
4
+ level: number;
5
+ name: string;
6
+ badgeColor: string;
7
+ onDismiss: () => void;
8
+ className?: string;
9
+ }
10
+ /** Auto-dismissing celebration burst for a level-up moment. Pure CSS
11
+ * animation, no dependency — particles are positioned/rotated via inline
12
+ * style so the same component works without a keyframe-per-particle
13
+ * stylesheet entry. */
14
+ declare function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }: LevelUpCelebrationProps): react_jsx_runtime.JSX.Element;
15
+
16
+ export { LevelUpCelebration, type LevelUpCelebrationProps };
@@ -0,0 +1,16 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface LevelUpCelebrationProps {
4
+ level: number;
5
+ name: string;
6
+ badgeColor: string;
7
+ onDismiss: () => void;
8
+ className?: string;
9
+ }
10
+ /** Auto-dismissing celebration burst for a level-up moment. Pure CSS
11
+ * animation, no dependency — particles are positioned/rotated via inline
12
+ * style so the same component works without a keyframe-per-particle
13
+ * stylesheet entry. */
14
+ declare function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }: LevelUpCelebrationProps): react_jsx_runtime.JSX.Element;
15
+
16
+ export { LevelUpCelebration, type LevelUpCelebrationProps };
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect } from "react";
4
+ import { LevelBadge } from "./level-badge.js";
5
+ import { cn } from "../../utils/cn.js";
6
+ const PARTICLE_COUNT = 14;
7
+ function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }) {
8
+ useEffect(() => {
9
+ const timer = setTimeout(onDismiss, 3e3);
10
+ return () => clearTimeout(timer);
11
+ }, [onDismiss]);
12
+ return /* @__PURE__ */ jsx(
13
+ "div",
14
+ {
15
+ role: "status",
16
+ "aria-live": "polite",
17
+ className: cn(
18
+ "fixed inset-0 z-[200] flex items-center justify-center bg-background/40 backdrop-blur-sm",
19
+ className
20
+ ),
21
+ onClick: onDismiss,
22
+ children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center gap-3 animate-in zoom-in-95 fade-in duration-300", children: [
23
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 -z-10", children: Array.from({ length: PARTICLE_COUNT }).map((_, i) => {
24
+ const angle = 360 / PARTICLE_COUNT * i;
25
+ const distance = 60 + i % 3 * 20;
26
+ return /* @__PURE__ */ jsx(
27
+ "span",
28
+ {
29
+ className: "absolute left-1/2 top-1/2 h-1.5 w-1.5 rounded-full animate-in fade-in zoom-in duration-700",
30
+ style: {
31
+ backgroundColor: badgeColor,
32
+ transform: `rotate(${angle}deg) translate(${distance}px) rotate(-${angle}deg)`
33
+ }
34
+ },
35
+ i
36
+ );
37
+ }) }),
38
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-bold uppercase tracking-widest text-muted-foreground", children: "Level up" }),
39
+ /* @__PURE__ */ jsx(LevelBadge, { level, name, badgeColor, size: "lg" })
40
+ ] })
41
+ }
42
+ );
43
+ }
44
+ export {
45
+ LevelUpCelebration
46
+ };
47
+ //# sourceMappingURL=level-up-celebration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/rewards/level-up-celebration.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { LevelBadge } from \"./level-badge.js\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface LevelUpCelebrationProps {\n level: number;\n name: string;\n badgeColor: string;\n onDismiss: () => void;\n className?: string;\n}\n\nconst PARTICLE_COUNT = 14;\n\n/** Auto-dismissing celebration burst for a level-up moment. Pure CSS\n * animation, no dependency — particles are positioned/rotated via inline\n * style so the same component works without a keyframe-per-particle\n * stylesheet entry. */\nexport function LevelUpCelebration({ level, name, badgeColor, onDismiss, className }: LevelUpCelebrationProps) {\n useEffect(() => {\n const timer = setTimeout(onDismiss, 3000);\n return () => clearTimeout(timer);\n }, [onDismiss]);\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n \"fixed inset-0 z-[200] flex items-center justify-center bg-background/40 backdrop-blur-sm\",\n className\n )}\n onClick={onDismiss}\n >\n <div className=\"relative flex flex-col items-center gap-3 animate-in zoom-in-95 fade-in duration-300\">\n <div className=\"pointer-events-none absolute inset-0 -z-10\">\n {Array.from({ length: PARTICLE_COUNT }).map((_, i) => {\n const angle = (360 / PARTICLE_COUNT) * i;\n const distance = 60 + (i % 3) * 20;\n return (\n <span\n key={i}\n className=\"absolute left-1/2 top-1/2 h-1.5 w-1.5 rounded-full animate-in fade-in zoom-in duration-700\"\n style={{\n backgroundColor: badgeColor,\n transform: `rotate(${angle}deg) translate(${distance}px) rotate(-${angle}deg)`,\n }}\n />\n );\n })}\n </div>\n <p className=\"text-sm font-bold uppercase tracking-widest text-muted-foreground\">Level up</p>\n <LevelBadge level={level} name={name} badgeColor={badgeColor} size=\"lg\" />\n </div>\n </div>\n );\n}\n"],"mappings":";AAoCM,SAMQ,KANR;AAlCN,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AAUnB,MAAM,iBAAiB;AAMhB,SAAS,mBAAmB,EAAE,OAAO,MAAM,YAAY,WAAW,UAAU,GAA4B;AAC7G,YAAU,MAAM;AACd,UAAM,QAAQ,WAAW,WAAW,GAAI;AACxC,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,SAAS,CAAC;AAEd,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS;AAAA,MAET,+BAAC,SAAI,WAAU,wFACb;AAAA,4BAAC,SAAI,WAAU,8CACZ,gBAAM,KAAK,EAAE,QAAQ,eAAe,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM;AACpD,gBAAM,QAAS,MAAM,iBAAkB;AACvC,gBAAM,WAAW,KAAM,IAAI,IAAK;AAChC,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,iBAAiB;AAAA,gBACjB,WAAW,UAAU,KAAK,kBAAkB,QAAQ,eAAe,KAAK;AAAA,cAC1E;AAAA;AAAA,YALK;AAAA,UAMP;AAAA,QAEJ,CAAC,GACH;AAAA,QACA,oBAAC,OAAE,WAAU,qEAAoE,sBAAQ;AAAA,QACzF,oBAAC,cAAW,OAAc,MAAY,YAAwB,MAAK,MAAK;AAAA,SAC1E;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -31,11 +31,29 @@ function createRewardToast(getRewardsConfig) {
31
31
  configPromise ?? (configPromise = getRewardsConfig());
32
32
  return configPromise;
33
33
  }
34
- return function rewardToast(actionType) {
34
+ return function rewardToast(actionType, snapshot) {
35
35
  loadConfig().then((config) => {
36
36
  const action = config.actions.find((a) => a.type === actionType);
37
37
  if (!action) return;
38
- (0, import_sonner.toast)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_xp_toast_content.XpToastContent, { xp: action.xp, label: action.label }), { duration: 3500 });
38
+ if (!snapshot) {
39
+ (0, import_sonner.toast)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_xp_toast_content.XpToastContent, { xp: action.xp, label: action.label }), { duration: 3500 });
40
+ return;
41
+ }
42
+ const level = config.levels.find((l) => l.level === snapshot.currentLevel);
43
+ const nextLevel = config.levels.find((l) => l.level === snapshot.currentLevel + 1);
44
+ (0, import_sonner.toast)(
45
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
46
+ import_xp_toast_content.XpToastContent,
47
+ {
48
+ xp: action.xp,
49
+ label: action.label,
50
+ totalXp: snapshot.totalXp,
51
+ levelXp: level?.xpRequired ?? 0,
52
+ nextLevelXp: nextLevel?.xpRequired ?? null
53
+ }
54
+ ),
55
+ { duration: 3500 }
56
+ );
39
57
  }).catch(() => {
40
58
  configPromise = null;
41
59
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/rewards/reward-toast.tsx"],"sourcesContent":["\"use client\";\n\nimport { toast } from \"sonner\";\nimport { XpToastContent } from \"./xp-toast-content.js\";\nimport type { ApiRewardsConfig } from \"@medialane/sdk\";\n\n/**\n * Optimistic XP feedback after a scoring action. Scores recompute on a\n * schedule, so this shows the action's configured value, never a balance.\n * Fire-and-forget: any failure is silent (rewards UI must never break a flow).\n *\n * Each app supplies its own `getRewardsConfig` (bound to its own\n * `MedialaneClient` singleton) — the caching/toast logic lives here once.\n */\nexport function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>) {\n let configPromise: Promise<ApiRewardsConfig> | null = null;\n function loadConfig() {\n configPromise ??= getRewardsConfig();\n return configPromise;\n }\n\n return function rewardToast(actionType: string): void {\n loadConfig()\n .then((config) => {\n const action = config.actions.find((a) => a.type === actionType);\n if (!action) return;\n toast(<XpToastContent xp={action.xp} label={action.label} />, { duration: 3500 });\n })\n .catch(() => {\n configPromise = null; // retry on the next action\n });\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0Bc;AAxBd,oBAAsB;AACtB,8BAA+B;AAWxB,SAAS,kBAAkB,kBAAmD;AACnF,MAAI,gBAAkD;AACtD,WAAS,aAAa;AACpB,sCAAkB,iBAAiB;AACnC,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,YAAY,YAA0B;AACpD,eAAW,EACR,KAAK,CAAC,WAAW;AAChB,YAAM,SAAS,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU;AAC/D,UAAI,CAAC,OAAQ;AACb,+BAAM,4CAAC,0CAAe,IAAI,OAAO,IAAI,OAAO,OAAO,OAAO,GAAI,EAAE,UAAU,KAAK,CAAC;AAAA,IAClF,CAAC,EACA,MAAM,MAAM;AACX,sBAAgB;AAAA,IAClB,CAAC;AAAA,EACL;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/rewards/reward-toast.tsx"],"sourcesContent":["\"use client\";\n\nimport { toast } from \"sonner\";\nimport { XpToastContent } from \"./xp-toast-content.js\";\nimport type { ApiRewardsConfig } from \"@medialane/sdk\";\n\nexport interface RewardToastSnapshot {\n totalXp: number;\n currentLevel: number;\n}\n\n/**\n * Optimistic XP feedback after a scoring action. Scores recompute on a\n * schedule, so this shows the action's configured value, never a balance.\n * Fire-and-forget: any failure is silent (rewards UI must never break a flow).\n *\n * Each app supplies its own `getRewardsConfig` (bound to its own\n * `MedialaneClient` singleton) — the caching/toast logic lives here once.\n */\nexport function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>) {\n let configPromise: Promise<ApiRewardsConfig> | null = null;\n function loadConfig() {\n configPromise ??= getRewardsConfig();\n return configPromise;\n }\n\n /**\n * @param snapshot Optional — when provided, the toast additionally shows\n * a progress bar toward the next level. Omit to get today's plain toast.\n */\n return function rewardToast(actionType: string, snapshot?: RewardToastSnapshot): void {\n loadConfig()\n .then((config) => {\n const action = config.actions.find((a) => a.type === actionType);\n if (!action) return;\n\n if (!snapshot) {\n toast(<XpToastContent xp={action.xp} label={action.label} />, { duration: 3500 });\n return;\n }\n\n const level = config.levels.find((l) => l.level === snapshot.currentLevel);\n const nextLevel = config.levels.find((l) => l.level === snapshot.currentLevel + 1);\n toast(\n <XpToastContent\n xp={action.xp}\n label={action.label}\n totalXp={snapshot.totalXp}\n levelXp={level?.xpRequired ?? 0}\n nextLevelXp={nextLevel?.xpRequired ?? null}\n />,\n { duration: 3500 }\n );\n })\n .catch(() => {\n configPromise = null; // retry on the next action\n });\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCgB;AAnChB,oBAAsB;AACtB,8BAA+B;AAgBxB,SAAS,kBAAkB,kBAAmD;AACnF,MAAI,gBAAkD;AACtD,WAAS,aAAa;AACpB,sCAAkB,iBAAiB;AACnC,WAAO;AAAA,EACT;AAMA,SAAO,SAAS,YAAY,YAAoB,UAAsC;AACpF,eAAW,EACR,KAAK,CAAC,WAAW;AAChB,YAAM,SAAS,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU;AAC/D,UAAI,CAAC,OAAQ;AAEb,UAAI,CAAC,UAAU;AACb,iCAAM,4CAAC,0CAAe,IAAI,OAAO,IAAI,OAAO,OAAO,OAAO,GAAI,EAAE,UAAU,KAAK,CAAC;AAChF;AAAA,MACF;AAEA,YAAM,QAAQ,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,UAAU,SAAS,YAAY;AACzE,YAAM,YAAY,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,UAAU,SAAS,eAAe,CAAC;AACjF;AAAA,QACE;AAAA,UAAC;AAAA;AAAA,YACC,IAAI,OAAO;AAAA,YACX,OAAO,OAAO;AAAA,YACd,SAAS,SAAS;AAAA,YAClB,SAAS,OAAO,cAAc;AAAA,YAC9B,aAAa,WAAW,cAAc;AAAA;AAAA,QACxC;AAAA,QACA,EAAE,UAAU,KAAK;AAAA,MACnB;AAAA,IACF,CAAC,EACA,MAAM,MAAM;AACX,sBAAgB;AAAA,IAClB,CAAC;AAAA,EACL;AACF;","names":[]}
@@ -1,5 +1,9 @@
1
1
  import { ApiRewardsConfig } from '@medialane/sdk';
2
2
 
3
+ interface RewardToastSnapshot {
4
+ totalXp: number;
5
+ currentLevel: number;
6
+ }
3
7
  /**
4
8
  * Optimistic XP feedback after a scoring action. Scores recompute on a
5
9
  * schedule, so this shows the action's configured value, never a balance.
@@ -8,6 +12,6 @@ import { ApiRewardsConfig } from '@medialane/sdk';
8
12
  * Each app supplies its own `getRewardsConfig` (bound to its own
9
13
  * `MedialaneClient` singleton) — the caching/toast logic lives here once.
10
14
  */
11
- declare function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>): (actionType: string) => void;
15
+ declare function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>): (actionType: string, snapshot?: RewardToastSnapshot) => void;
12
16
 
13
- export { createRewardToast };
17
+ export { type RewardToastSnapshot, createRewardToast };
@@ -1,5 +1,9 @@
1
1
  import { ApiRewardsConfig } from '@medialane/sdk';
2
2
 
3
+ interface RewardToastSnapshot {
4
+ totalXp: number;
5
+ currentLevel: number;
6
+ }
3
7
  /**
4
8
  * Optimistic XP feedback after a scoring action. Scores recompute on a
5
9
  * schedule, so this shows the action's configured value, never a balance.
@@ -8,6 +12,6 @@ import { ApiRewardsConfig } from '@medialane/sdk';
8
12
  * Each app supplies its own `getRewardsConfig` (bound to its own
9
13
  * `MedialaneClient` singleton) — the caching/toast logic lives here once.
10
14
  */
11
- declare function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>): (actionType: string) => void;
15
+ declare function createRewardToast(getRewardsConfig: () => Promise<ApiRewardsConfig>): (actionType: string, snapshot?: RewardToastSnapshot) => void;
12
16
 
13
- export { createRewardToast };
17
+ export { type RewardToastSnapshot, createRewardToast };