@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.
- package/dist/components/community-rewards-section.cjs +123 -0
- package/dist/components/community-rewards-section.cjs.map +1 -0
- package/dist/components/community-rewards-section.d.cts +15 -0
- package/dist/components/community-rewards-section.d.ts +15 -0
- package/dist/components/community-rewards-section.js +89 -0
- package/dist/components/community-rewards-section.js.map +1 -0
- package/dist/components/creator-airdrop-banner.cjs +79 -0
- package/dist/components/creator-airdrop-banner.cjs.map +1 -0
- package/dist/components/creator-airdrop-banner.d.cts +9 -0
- package/dist/components/creator-airdrop-banner.d.ts +9 -0
- package/dist/components/creator-airdrop-banner.js +45 -0
- package/dist/components/creator-airdrop-banner.js.map +1 -0
- 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/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 +20 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/creators-fund-section.cjs +0 -139
- package/dist/components/creators-fund-section.cjs.map +0 -1
- package/dist/components/creators-fund-section.d.cts +0 -26
- package/dist/components/creators-fund-section.d.ts +0 -26
- package/dist/components/creators-fund-section.js +0 -105
- 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
|
|
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 ("
|
|
11
|
-
*
|
|
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 ("
|
|
11
|
-
*
|
|
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
|
|
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
|
-
|
|
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;
|
|
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 };
|