@medialane/ui 0.36.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/rewards/badge-shelf.cjs +90 -0
- package/dist/components/rewards/badge-shelf.cjs.map +1 -0
- package/dist/components/rewards/badge-shelf.d.cts +24 -0
- package/dist/components/rewards/badge-shelf.d.ts +24 -0
- package/dist/components/rewards/badge-shelf.js +56 -0
- package/dist/components/rewards/badge-shelf.js.map +1 -0
- package/dist/components/rewards/leaderboard-table.cjs +96 -0
- package/dist/components/rewards/leaderboard-table.cjs.map +1 -0
- package/dist/components/rewards/leaderboard-table.d.cts +34 -0
- package/dist/components/rewards/leaderboard-table.d.ts +34 -0
- package/dist/components/rewards/leaderboard-table.js +71 -0
- package/dist/components/rewards/leaderboard-table.js.map +1 -0
- package/dist/components/rewards/level-badge.cjs +60 -0
- package/dist/components/rewards/level-badge.cjs.map +1 -0
- package/dist/components/rewards/level-badge.d.cts +14 -0
- package/dist/components/rewards/level-badge.d.ts +14 -0
- package/dist/components/rewards/level-badge.js +36 -0
- package/dist/components/rewards/level-badge.js.map +1 -0
- package/dist/components/rewards/level-ladder.cjs +54 -0
- package/dist/components/rewards/level-ladder.cjs.map +1 -0
- package/dist/components/rewards/level-ladder.d.cts +17 -0
- package/dist/components/rewards/level-ladder.d.ts +17 -0
- package/dist/components/rewards/level-ladder.js +30 -0
- package/dist/components/rewards/level-ladder.js.map +1 -0
- package/dist/components/rewards/score-summary-card.cjs +83 -0
- package/dist/components/rewards/score-summary-card.cjs.map +1 -0
- package/dist/components/rewards/score-summary-card.d.cts +26 -0
- package/dist/components/rewards/score-summary-card.d.ts +26 -0
- package/dist/components/rewards/score-summary-card.js +59 -0
- package/dist/components/rewards/score-summary-card.js.map +1 -0
- package/dist/components/rewards/xp-progress.cjs +81 -0
- package/dist/components/rewards/xp-progress.cjs.map +1 -0
- package/dist/components/rewards/xp-progress.d.cts +18 -0
- package/dist/components/rewards/xp-progress.d.ts +18 -0
- package/dist/components/rewards/xp-progress.js +57 -0
- package/dist/components/rewards/xp-progress.js.map +1 -0
- package/dist/components/rewards/xp-toast-content.cjs +49 -0
- package/dist/components/rewards/xp-toast-content.cjs.map +1 -0
- package/dist/components/rewards/xp-toast-content.d.cts +14 -0
- package/dist/components/rewards/xp-toast-content.d.ts +14 -0
- package/dist/components/rewards/xp-toast-content.js +25 -0
- package/dist/components/rewards/xp-toast-content.js.map +1 -0
- package/dist/index.d.cts +9 -128
- package/dist/index.d.ts +9 -128
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
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 level_ladder_exports = {};
|
|
20
|
+
__export(level_ladder_exports, {
|
|
21
|
+
LevelLadder: () => LevelLadder
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(level_ladder_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_cn = require("../../utils/cn.js");
|
|
26
|
+
function LevelLadder({ levels, currentLevel, className }) {
|
|
27
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("flex gap-2 overflow-x-auto pb-2", className), children: levels.map((l) => {
|
|
28
|
+
const state = l.level < currentLevel ? "done" : l.level === currentLevel ? "current" : "future";
|
|
29
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
30
|
+
"div",
|
|
31
|
+
{
|
|
32
|
+
title: `${l.xpRequired.toLocaleString()} XP`,
|
|
33
|
+
className: (0, import_cn.cn)(
|
|
34
|
+
"flex shrink-0 select-none flex-col items-center gap-0.5 rounded-lg border px-2.5 py-1.5",
|
|
35
|
+
state === "future" && "opacity-45"
|
|
36
|
+
),
|
|
37
|
+
style: {
|
|
38
|
+
borderColor: state === "current" ? l.badgeColor : `${l.badgeColor}40`,
|
|
39
|
+
backgroundColor: state === "current" ? `${l.badgeColor}22` : `${l.badgeColor}0d`
|
|
40
|
+
},
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[10px] font-black tabular-nums", style: { color: l.badgeColor }, children: l.level }),
|
|
43
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "whitespace-nowrap text-[10px] font-semibold", style: { color: l.badgeColor }, children: l.name })
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
l.level
|
|
47
|
+
);
|
|
48
|
+
}) });
|
|
49
|
+
}
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
LevelLadder
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=level-ladder.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/level-ladder.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelLadderProps {\n levels: { level: number; name: string; xpRequired: number; badgeColor: string }[];\n currentLevel: number;\n className?: string;\n}\n\n/** The full level arc as a horizontally scrollable chip rail; the current\n * level is highlighted, passed levels render solid, future ones muted. */\nexport function LevelLadder({ levels, currentLevel, className }: LevelLadderProps) {\n return (\n <div className={cn(\"flex gap-2 overflow-x-auto pb-2\", className)}>\n {levels.map((l) => {\n const state = l.level < currentLevel ? \"done\" : l.level === currentLevel ? \"current\" : \"future\";\n return (\n <div\n key={l.level}\n title={`${l.xpRequired.toLocaleString()} XP`}\n className={cn(\n \"flex shrink-0 select-none flex-col items-center gap-0.5 rounded-lg border px-2.5 py-1.5\",\n state === \"future\" && \"opacity-45\"\n )}\n style={{\n borderColor: state === \"current\" ? l.badgeColor : `${l.badgeColor}40`,\n backgroundColor: state === \"current\" ? `${l.badgeColor}22` : `${l.badgeColor}0d`,\n }}\n >\n <span className=\"text-[10px] font-black tabular-nums\" style={{ color: l.badgeColor }}>\n {l.level}\n </span>\n <span className=\"whitespace-nowrap text-[10px] font-semibold\" style={{ color: l.badgeColor }}>\n {l.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBU;AAhBV,gBAAmB;AAUZ,SAAS,YAAY,EAAE,QAAQ,cAAc,UAAU,GAAqB;AACjF,SACE,4CAAC,SAAI,eAAW,cAAG,mCAAmC,SAAS,GAC5D,iBAAO,IAAI,CAAC,MAAM;AACjB,UAAM,QAAQ,EAAE,QAAQ,eAAe,SAAS,EAAE,UAAU,eAAe,YAAY;AACvF,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,GAAG,EAAE,WAAW,eAAe,CAAC;AAAA,QACvC,eAAW;AAAA,UACT;AAAA,UACA,UAAU,YAAY;AAAA,QACxB;AAAA,QACA,OAAO;AAAA,UACL,aAAa,UAAU,YAAY,EAAE,aAAa,GAAG,EAAE,UAAU;AAAA,UACjE,iBAAiB,UAAU,YAAY,GAAG,EAAE,UAAU,OAAO,GAAG,EAAE,UAAU;AAAA,QAC9E;AAAA,QAEA;AAAA,sDAAC,UAAK,WAAU,uCAAsC,OAAO,EAAE,OAAO,EAAE,WAAW,GAChF,YAAE,OACL;AAAA,UACA,4CAAC,UAAK,WAAU,+CAA8C,OAAO,EAAE,OAAO,EAAE,WAAW,GACxF,YAAE,MACL;AAAA;AAAA;AAAA,MAhBK,EAAE;AAAA,IAiBT;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LevelLadderProps {
|
|
4
|
+
levels: {
|
|
5
|
+
level: number;
|
|
6
|
+
name: string;
|
|
7
|
+
xpRequired: number;
|
|
8
|
+
badgeColor: string;
|
|
9
|
+
}[];
|
|
10
|
+
currentLevel: number;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** The full level arc as a horizontally scrollable chip rail; the current
|
|
14
|
+
* level is highlighted, passed levels render solid, future ones muted. */
|
|
15
|
+
declare function LevelLadder({ levels, currentLevel, className }: LevelLadderProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
|
|
17
|
+
export { LevelLadder, type LevelLadderProps };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LevelLadderProps {
|
|
4
|
+
levels: {
|
|
5
|
+
level: number;
|
|
6
|
+
name: string;
|
|
7
|
+
xpRequired: number;
|
|
8
|
+
badgeColor: string;
|
|
9
|
+
}[];
|
|
10
|
+
currentLevel: number;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** The full level arc as a horizontally scrollable chip rail; the current
|
|
14
|
+
* level is highlighted, passed levels render solid, future ones muted. */
|
|
15
|
+
declare function LevelLadder({ levels, currentLevel, className }: LevelLadderProps): react_jsx_runtime.JSX.Element;
|
|
16
|
+
|
|
17
|
+
export { LevelLadder, type LevelLadderProps };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
function LevelLadder({ levels, currentLevel, className }) {
|
|
4
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex gap-2 overflow-x-auto pb-2", className), children: levels.map((l) => {
|
|
5
|
+
const state = l.level < currentLevel ? "done" : l.level === currentLevel ? "current" : "future";
|
|
6
|
+
return /* @__PURE__ */ jsxs(
|
|
7
|
+
"div",
|
|
8
|
+
{
|
|
9
|
+
title: `${l.xpRequired.toLocaleString()} XP`,
|
|
10
|
+
className: cn(
|
|
11
|
+
"flex shrink-0 select-none flex-col items-center gap-0.5 rounded-lg border px-2.5 py-1.5",
|
|
12
|
+
state === "future" && "opacity-45"
|
|
13
|
+
),
|
|
14
|
+
style: {
|
|
15
|
+
borderColor: state === "current" ? l.badgeColor : `${l.badgeColor}40`,
|
|
16
|
+
backgroundColor: state === "current" ? `${l.badgeColor}22` : `${l.badgeColor}0d`
|
|
17
|
+
},
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-black tabular-nums", style: { color: l.badgeColor }, children: l.level }),
|
|
20
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-[10px] font-semibold", style: { color: l.badgeColor }, children: l.name })
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
l.level
|
|
24
|
+
);
|
|
25
|
+
}) });
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
LevelLadder
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=level-ladder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/level-ladder.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface LevelLadderProps {\n levels: { level: number; name: string; xpRequired: number; badgeColor: string }[];\n currentLevel: number;\n className?: string;\n}\n\n/** The full level arc as a horizontally scrollable chip rail; the current\n * level is highlighted, passed levels render solid, future ones muted. */\nexport function LevelLadder({ levels, currentLevel, className }: LevelLadderProps) {\n return (\n <div className={cn(\"flex gap-2 overflow-x-auto pb-2\", className)}>\n {levels.map((l) => {\n const state = l.level < currentLevel ? \"done\" : l.level === currentLevel ? \"current\" : \"future\";\n return (\n <div\n key={l.level}\n title={`${l.xpRequired.toLocaleString()} XP`}\n className={cn(\n \"flex shrink-0 select-none flex-col items-center gap-0.5 rounded-lg border px-2.5 py-1.5\",\n state === \"future\" && \"opacity-45\"\n )}\n style={{\n borderColor: state === \"current\" ? l.badgeColor : `${l.badgeColor}40`,\n backgroundColor: state === \"current\" ? `${l.badgeColor}22` : `${l.badgeColor}0d`,\n }}\n >\n <span className=\"text-[10px] font-black tabular-nums\" style={{ color: l.badgeColor }}>\n {l.level}\n </span>\n <span className=\"whitespace-nowrap text-[10px] font-semibold\" style={{ color: l.badgeColor }}>\n {l.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"AAgBU,SAYE,KAZF;AAhBV,SAAS,UAAU;AAUZ,SAAS,YAAY,EAAE,QAAQ,cAAc,UAAU,GAAqB;AACjF,SACE,oBAAC,SAAI,WAAW,GAAG,mCAAmC,SAAS,GAC5D,iBAAO,IAAI,CAAC,MAAM;AACjB,UAAM,QAAQ,EAAE,QAAQ,eAAe,SAAS,EAAE,UAAU,eAAe,YAAY;AACvF,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,GAAG,EAAE,WAAW,eAAe,CAAC;AAAA,QACvC,WAAW;AAAA,UACT;AAAA,UACA,UAAU,YAAY;AAAA,QACxB;AAAA,QACA,OAAO;AAAA,UACL,aAAa,UAAU,YAAY,EAAE,aAAa,GAAG,EAAE,UAAU;AAAA,UACjE,iBAAiB,UAAU,YAAY,GAAG,EAAE,UAAU,OAAO,GAAG,EAAE,UAAU;AAAA,QAC9E;AAAA,QAEA;AAAA,8BAAC,UAAK,WAAU,uCAAsC,OAAO,EAAE,OAAO,EAAE,WAAW,GAChF,YAAE,OACL;AAAA,UACA,oBAAC,UAAK,WAAU,+CAA8C,OAAO,EAAE,OAAO,EAAE,WAAW,GACxF,YAAE,MACL;AAAA;AAAA;AAAA,MAhBK,EAAE;AAAA,IAiBT;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
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 score_summary_card_exports = {};
|
|
20
|
+
__export(score_summary_card_exports, {
|
|
21
|
+
ScoreSummaryCard: () => ScoreSummaryCard
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(score_summary_card_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_cn = require("../../utils/cn.js");
|
|
26
|
+
var import_level_badge = require("./level-badge.js");
|
|
27
|
+
var import_xp_progress = require("./xp-progress.js");
|
|
28
|
+
var import_badge_shelf = require("./badge-shelf.js");
|
|
29
|
+
function ScoreSummaryCard({
|
|
30
|
+
level,
|
|
31
|
+
levelName,
|
|
32
|
+
badgeColor,
|
|
33
|
+
totalXp,
|
|
34
|
+
levelXp,
|
|
35
|
+
nextLevel,
|
|
36
|
+
topBadges,
|
|
37
|
+
href,
|
|
38
|
+
className
|
|
39
|
+
}) {
|
|
40
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_cn.cn)("rounded-xl border border-border bg-card p-4 sm:p-5", className), children: [
|
|
41
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative flex items-center justify-center", children: [
|
|
43
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
44
|
+
import_xp_progress.XpProgress,
|
|
45
|
+
{
|
|
46
|
+
variant: "ring",
|
|
47
|
+
size: 52,
|
|
48
|
+
totalXp,
|
|
49
|
+
levelXp,
|
|
50
|
+
nextLevelXp: nextLevel?.xpRequired ?? null,
|
|
51
|
+
badgeColor
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute text-sm font-black", style: { color: badgeColor }, children: level })
|
|
55
|
+
] }),
|
|
56
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
57
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_level_badge.LevelBadge, { level, name: levelName, badgeColor, size: "md" }),
|
|
58
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
59
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-semibold text-foreground", children: [
|
|
60
|
+
totalXp.toLocaleString(),
|
|
61
|
+
" XP"
|
|
62
|
+
] }),
|
|
63
|
+
nextLevel && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
64
|
+
" \xB7 ",
|
|
65
|
+
(nextLevel.xpRequired - totalXp).toLocaleString(),
|
|
66
|
+
" XP to Lv.",
|
|
67
|
+
nextLevel.level,
|
|
68
|
+
" ",
|
|
69
|
+
nextLevel.name
|
|
70
|
+
] })
|
|
71
|
+
] })
|
|
72
|
+
] })
|
|
73
|
+
] }),
|
|
74
|
+
topBadges && topBadges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_badge_shelf.BadgeShelf, { badges: topBadges, className: "mt-3" })
|
|
75
|
+
] });
|
|
76
|
+
if (!href) return body;
|
|
77
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, className: "block active:opacity-80", children: body });
|
|
78
|
+
}
|
|
79
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
80
|
+
0 && (module.exports = {
|
|
81
|
+
ScoreSummaryCard
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=score-summary-card.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/score-summary-card.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\nimport { LevelBadge } from \"./level-badge.js\";\nimport { XpProgress } from \"./xp-progress.js\";\nimport { BadgeShelf, type BadgeShelfBadge } from \"./badge-shelf.js\";\n\nexport interface ScoreSummaryCardProps {\n level: number;\n levelName: string;\n badgeColor: string;\n totalXp: number;\n /** XP required to reach the current level. */\n levelXp: number;\n nextLevel: { level: number; name: string; xpRequired: number } | null;\n /** A few earned badges to preview (already limited by the caller). */\n topBadges?: BadgeShelfBadge[];\n /** Where the card links (\"/rewards\"); rendered as a plain anchor. */\n href?: string;\n className?: string;\n}\n\n/** Compact score overview for portfolio/profile surfaces: level ring, XP,\n * next-level progress, and a short badge preview. */\nexport function ScoreSummaryCard({\n level,\n levelName,\n badgeColor,\n totalXp,\n levelXp,\n nextLevel,\n topBadges,\n href,\n className,\n}: ScoreSummaryCardProps) {\n const body = (\n <div className={cn(\"rounded-xl border border-border bg-card p-4 sm:p-5\", className)}>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative flex items-center justify-center\">\n <XpProgress\n variant=\"ring\"\n size={52}\n totalXp={totalXp}\n levelXp={levelXp}\n nextLevelXp={nextLevel?.xpRequired ?? null}\n badgeColor={badgeColor}\n />\n <span className=\"absolute text-sm font-black\" style={{ color: badgeColor }}>\n {level}\n </span>\n </div>\n <div className=\"min-w-0 flex-1\">\n <LevelBadge level={level} name={levelName} badgeColor={badgeColor} size=\"md\" />\n <p className=\"mt-1 text-sm text-muted-foreground\">\n <span className=\"font-semibold text-foreground\">{totalXp.toLocaleString()} XP</span>\n {nextLevel && (\n <>\n {\" · \"}\n {(nextLevel.xpRequired - totalXp).toLocaleString()} XP to Lv.{nextLevel.level} {nextLevel.name}\n </>\n )}\n </p>\n </div>\n </div>\n {topBadges && topBadges.length > 0 && <BadgeShelf badges={topBadges} className=\"mt-3\" />}\n </div>\n );\n\n if (!href) return body;\n return (\n <a href={href} className=\"block active:opacity-80\">\n {body}\n </a>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCQ;AApCR,gBAAmB;AACnB,yBAA2B;AAC3B,yBAA2B;AAC3B,yBAAiD;AAmB1C,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,OACJ,6CAAC,SAAI,eAAW,cAAG,sDAAsD,SAAS,GAChF;AAAA,iDAAC,SAAI,WAAU,2BACb;AAAA,mDAAC,SAAI,WAAU,6CACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,aAAa,WAAW,cAAc;AAAA,YACtC;AAAA;AAAA,QACF;AAAA,QACA,4CAAC,UAAK,WAAU,+BAA8B,OAAO,EAAE,OAAO,WAAW,GACtE,iBACH;AAAA,SACF;AAAA,MACA,6CAAC,SAAI,WAAU,kBACb;AAAA,oDAAC,iCAAW,OAAc,MAAM,WAAW,YAAwB,MAAK,MAAK;AAAA,QAC7E,6CAAC,OAAE,WAAU,sCACX;AAAA,uDAAC,UAAK,WAAU,iCAAiC;AAAA,oBAAQ,eAAe;AAAA,YAAE;AAAA,aAAG;AAAA,UAC5E,aACC,4EACG;AAAA;AAAA,aACC,UAAU,aAAa,SAAS,eAAe;AAAA,YAAE;AAAA,YAAW,UAAU;AAAA,YAAM;AAAA,YAAE,UAAU;AAAA,aAC5F;AAAA,WAEJ;AAAA,SACF;AAAA,OACF;AAAA,IACC,aAAa,UAAU,SAAS,KAAK,4CAAC,iCAAW,QAAQ,WAAW,WAAU,QAAO;AAAA,KACxF;AAGF,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,4CAAC,OAAE,MAAY,WAAU,2BACtB,gBACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { BadgeShelfBadge } from './badge-shelf.cjs';
|
|
3
|
+
|
|
4
|
+
interface ScoreSummaryCardProps {
|
|
5
|
+
level: number;
|
|
6
|
+
levelName: string;
|
|
7
|
+
badgeColor: string;
|
|
8
|
+
totalXp: number;
|
|
9
|
+
/** XP required to reach the current level. */
|
|
10
|
+
levelXp: number;
|
|
11
|
+
nextLevel: {
|
|
12
|
+
level: number;
|
|
13
|
+
name: string;
|
|
14
|
+
xpRequired: number;
|
|
15
|
+
} | null;
|
|
16
|
+
/** A few earned badges to preview (already limited by the caller). */
|
|
17
|
+
topBadges?: BadgeShelfBadge[];
|
|
18
|
+
/** Where the card links ("/rewards"); rendered as a plain anchor. */
|
|
19
|
+
href?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Compact score overview for portfolio/profile surfaces: level ring, XP,
|
|
23
|
+
* next-level progress, and a short badge preview. */
|
|
24
|
+
declare function ScoreSummaryCard({ level, levelName, badgeColor, totalXp, levelXp, nextLevel, topBadges, href, className, }: ScoreSummaryCardProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export { ScoreSummaryCard, type ScoreSummaryCardProps };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { BadgeShelfBadge } from './badge-shelf.js';
|
|
3
|
+
|
|
4
|
+
interface ScoreSummaryCardProps {
|
|
5
|
+
level: number;
|
|
6
|
+
levelName: string;
|
|
7
|
+
badgeColor: string;
|
|
8
|
+
totalXp: number;
|
|
9
|
+
/** XP required to reach the current level. */
|
|
10
|
+
levelXp: number;
|
|
11
|
+
nextLevel: {
|
|
12
|
+
level: number;
|
|
13
|
+
name: string;
|
|
14
|
+
xpRequired: number;
|
|
15
|
+
} | null;
|
|
16
|
+
/** A few earned badges to preview (already limited by the caller). */
|
|
17
|
+
topBadges?: BadgeShelfBadge[];
|
|
18
|
+
/** Where the card links ("/rewards"); rendered as a plain anchor. */
|
|
19
|
+
href?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Compact score overview for portfolio/profile surfaces: level ring, XP,
|
|
23
|
+
* next-level progress, and a short badge preview. */
|
|
24
|
+
declare function ScoreSummaryCard({ level, levelName, badgeColor, totalXp, levelXp, nextLevel, topBadges, href, className, }: ScoreSummaryCardProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export { ScoreSummaryCard, type ScoreSummaryCardProps };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
import { LevelBadge } from "./level-badge.js";
|
|
4
|
+
import { XpProgress } from "./xp-progress.js";
|
|
5
|
+
import { BadgeShelf } from "./badge-shelf.js";
|
|
6
|
+
function ScoreSummaryCard({
|
|
7
|
+
level,
|
|
8
|
+
levelName,
|
|
9
|
+
badgeColor,
|
|
10
|
+
totalXp,
|
|
11
|
+
levelXp,
|
|
12
|
+
nextLevel,
|
|
13
|
+
topBadges,
|
|
14
|
+
href,
|
|
15
|
+
className
|
|
16
|
+
}) {
|
|
17
|
+
const body = /* @__PURE__ */ jsxs("div", { className: cn("rounded-xl border border-border bg-card p-4 sm:p-5", className), children: [
|
|
18
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
19
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
XpProgress,
|
|
22
|
+
{
|
|
23
|
+
variant: "ring",
|
|
24
|
+
size: 52,
|
|
25
|
+
totalXp,
|
|
26
|
+
levelXp,
|
|
27
|
+
nextLevelXp: nextLevel?.xpRequired ?? null,
|
|
28
|
+
badgeColor
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: "absolute text-sm font-black", style: { color: badgeColor }, children: level })
|
|
32
|
+
] }),
|
|
33
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
34
|
+
/* @__PURE__ */ jsx(LevelBadge, { level, name: levelName, badgeColor, size: "md" }),
|
|
35
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
36
|
+
/* @__PURE__ */ jsxs("span", { className: "font-semibold text-foreground", children: [
|
|
37
|
+
totalXp.toLocaleString(),
|
|
38
|
+
" XP"
|
|
39
|
+
] }),
|
|
40
|
+
nextLevel && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
|
+
" \xB7 ",
|
|
42
|
+
(nextLevel.xpRequired - totalXp).toLocaleString(),
|
|
43
|
+
" XP to Lv.",
|
|
44
|
+
nextLevel.level,
|
|
45
|
+
" ",
|
|
46
|
+
nextLevel.name
|
|
47
|
+
] })
|
|
48
|
+
] })
|
|
49
|
+
] })
|
|
50
|
+
] }),
|
|
51
|
+
topBadges && topBadges.length > 0 && /* @__PURE__ */ jsx(BadgeShelf, { badges: topBadges, className: "mt-3" })
|
|
52
|
+
] });
|
|
53
|
+
if (!href) return body;
|
|
54
|
+
return /* @__PURE__ */ jsx("a", { href, className: "block active:opacity-80", children: body });
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
ScoreSummaryCard
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=score-summary-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/score-summary-card.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\nimport { LevelBadge } from \"./level-badge.js\";\nimport { XpProgress } from \"./xp-progress.js\";\nimport { BadgeShelf, type BadgeShelfBadge } from \"./badge-shelf.js\";\n\nexport interface ScoreSummaryCardProps {\n level: number;\n levelName: string;\n badgeColor: string;\n totalXp: number;\n /** XP required to reach the current level. */\n levelXp: number;\n nextLevel: { level: number; name: string; xpRequired: number } | null;\n /** A few earned badges to preview (already limited by the caller). */\n topBadges?: BadgeShelfBadge[];\n /** Where the card links (\"/rewards\"); rendered as a plain anchor. */\n href?: string;\n className?: string;\n}\n\n/** Compact score overview for portfolio/profile surfaces: level ring, XP,\n * next-level progress, and a short badge preview. */\nexport function ScoreSummaryCard({\n level,\n levelName,\n badgeColor,\n totalXp,\n levelXp,\n nextLevel,\n topBadges,\n href,\n className,\n}: ScoreSummaryCardProps) {\n const body = (\n <div className={cn(\"rounded-xl border border-border bg-card p-4 sm:p-5\", className)}>\n <div className=\"flex items-center gap-3\">\n <div className=\"relative flex items-center justify-center\">\n <XpProgress\n variant=\"ring\"\n size={52}\n totalXp={totalXp}\n levelXp={levelXp}\n nextLevelXp={nextLevel?.xpRequired ?? null}\n badgeColor={badgeColor}\n />\n <span className=\"absolute text-sm font-black\" style={{ color: badgeColor }}>\n {level}\n </span>\n </div>\n <div className=\"min-w-0 flex-1\">\n <LevelBadge level={level} name={levelName} badgeColor={badgeColor} size=\"md\" />\n <p className=\"mt-1 text-sm text-muted-foreground\">\n <span className=\"font-semibold text-foreground\">{totalXp.toLocaleString()} XP</span>\n {nextLevel && (\n <>\n {\" · \"}\n {(nextLevel.xpRequired - totalXp).toLocaleString()} XP to Lv.{nextLevel.level} {nextLevel.name}\n </>\n )}\n </p>\n </div>\n </div>\n {topBadges && topBadges.length > 0 && <BadgeShelf badges={topBadges} className=\"mt-3\" />}\n </div>\n );\n\n if (!href) return body;\n return (\n <a href={href} className=\"block active:opacity-80\">\n {body}\n </a>\n );\n}\n"],"mappings":"AAoCQ,SAkBM,UAjBJ,KADF;AApCR,SAAS,UAAU;AACnB,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,kBAAwC;AAmB1C,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,OACJ,qBAAC,SAAI,WAAW,GAAG,sDAAsD,SAAS,GAChF;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,2BAAC,SAAI,WAAU,6CACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,aAAa,WAAW,cAAc;AAAA,YACtC;AAAA;AAAA,QACF;AAAA,QACA,oBAAC,UAAK,WAAU,+BAA8B,OAAO,EAAE,OAAO,WAAW,GACtE,iBACH;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,kBACb;AAAA,4BAAC,cAAW,OAAc,MAAM,WAAW,YAAwB,MAAK,MAAK;AAAA,QAC7E,qBAAC,OAAE,WAAU,sCACX;AAAA,+BAAC,UAAK,WAAU,iCAAiC;AAAA,oBAAQ,eAAe;AAAA,YAAE;AAAA,aAAG;AAAA,UAC5E,aACC,iCACG;AAAA;AAAA,aACC,UAAU,aAAa,SAAS,eAAe;AAAA,YAAE;AAAA,YAAW,UAAU;AAAA,YAAM;AAAA,YAAE,UAAU;AAAA,aAC5F;AAAA,WAEJ;AAAA,SACF;AAAA,OACF;AAAA,IACC,aAAa,UAAU,SAAS,KAAK,oBAAC,cAAW,QAAQ,WAAW,WAAU,QAAO;AAAA,KACxF;AAGF,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,oBAAC,OAAE,MAAY,WAAU,2BACtB,gBACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
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 xp_progress_exports = {};
|
|
20
|
+
__export(xp_progress_exports, {
|
|
21
|
+
XpProgress: () => XpProgress
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(xp_progress_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_cn = require("../../utils/cn.js");
|
|
26
|
+
function progressPct({ totalXp, levelXp, nextLevelXp }) {
|
|
27
|
+
if (nextLevelXp === null || nextLevelXp <= levelXp) return 100;
|
|
28
|
+
return Math.min(100, Math.max(0, Math.round((totalXp - levelXp) / (nextLevelXp - levelXp) * 100)));
|
|
29
|
+
}
|
|
30
|
+
function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant = "bar", size = 40, className }) {
|
|
31
|
+
const pct = progressPct({ totalXp, levelXp, nextLevelXp });
|
|
32
|
+
if (variant === "ring") {
|
|
33
|
+
const stroke = Math.max(2.5, size / 12);
|
|
34
|
+
const radius = (size - stroke) / 2;
|
|
35
|
+
const circumference = 2 * Math.PI * radius;
|
|
36
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
37
|
+
"svg",
|
|
38
|
+
{
|
|
39
|
+
width: size,
|
|
40
|
+
height: size,
|
|
41
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
42
|
+
className: (0, import_cn.cn)("shrink-0 -rotate-90", className),
|
|
43
|
+
role: "img",
|
|
44
|
+
"aria-label": `${pct}% toward the next level`,
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", strokeWidth: stroke, className: "stroke-border" }),
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
48
|
+
"circle",
|
|
49
|
+
{
|
|
50
|
+
cx: size / 2,
|
|
51
|
+
cy: size / 2,
|
|
52
|
+
r: radius,
|
|
53
|
+
fill: "none",
|
|
54
|
+
strokeWidth: stroke,
|
|
55
|
+
strokeLinecap: "round",
|
|
56
|
+
stroke: badgeColor,
|
|
57
|
+
strokeDasharray: circumference,
|
|
58
|
+
strokeDashoffset: circumference * (1 - pct / 100)
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
className: (0, import_cn.cn)("h-2 w-full overflow-hidden rounded-full bg-border/60", className),
|
|
69
|
+
role: "progressbar",
|
|
70
|
+
"aria-valuenow": pct,
|
|
71
|
+
"aria-valuemin": 0,
|
|
72
|
+
"aria-valuemax": 100,
|
|
73
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-full rounded-full transition-[width]", style: { width: `${pct}%`, backgroundColor: badgeColor } })
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
78
|
+
0 && (module.exports = {
|
|
79
|
+
XpProgress
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=xp-progress.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/xp-progress.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface XpProgressProps {\n totalXp: number;\n /** XP required to reach the current level. */\n levelXp: number;\n /** XP required for the next level; null at max level (renders full). */\n nextLevelXp: number | null;\n badgeColor: string;\n variant?: \"bar\" | \"ring\";\n /** Ring diameter in px (ring variant only). */\n size?: number;\n className?: string;\n}\n\nfunction progressPct({ totalXp, levelXp, nextLevelXp }: Pick<XpProgressProps, \"totalXp\" | \"levelXp\" | \"nextLevelXp\">): number {\n if (nextLevelXp === null || nextLevelXp <= levelXp) return 100;\n return Math.min(100, Math.max(0, Math.round(((totalXp - levelXp) / (nextLevelXp - levelXp)) * 100)));\n}\n\n/** XP progress toward the next level, as a rounded bar or an SVG ring. */\nexport function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant = \"bar\", size = 40, className }: XpProgressProps) {\n const pct = progressPct({ totalXp, levelXp, nextLevelXp });\n\n if (variant === \"ring\") {\n const stroke = Math.max(2.5, size / 12);\n const radius = (size - stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n className={cn(\"shrink-0 -rotate-90\", className)}\n role=\"img\"\n aria-label={`${pct}% toward the next level`}\n >\n <circle cx={size / 2} cy={size / 2} r={radius} fill=\"none\" strokeWidth={stroke} className=\"stroke-border\" />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n stroke={badgeColor}\n strokeDasharray={circumference}\n strokeDashoffset={circumference * (1 - pct / 100)}\n />\n </svg>\n );\n }\n\n return (\n <div\n className={cn(\"h-2 w-full overflow-hidden rounded-full bg-border/60\", className)}\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div className=\"h-full rounded-full transition-[width]\" style={{ width: `${pct}%`, backgroundColor: badgeColor }} />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BM;AA7BN,gBAAmB;AAenB,SAAS,YAAY,EAAE,SAAS,SAAS,YAAY,GAAyE;AAC5H,MAAI,gBAAgB,QAAQ,eAAe,QAAS,QAAO;AAC3D,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,OAAQ,UAAU,YAAY,cAAc,WAAY,GAAG,CAAC,CAAC;AACrG;AAGO,SAAS,WAAW,EAAE,SAAS,SAAS,aAAa,YAAY,UAAU,OAAO,OAAO,IAAI,UAAU,GAAoB;AAChI,QAAM,MAAM,YAAY,EAAE,SAAS,SAAS,YAAY,CAAC;AAEzD,MAAI,YAAY,QAAQ;AACtB,UAAM,SAAS,KAAK,IAAI,KAAK,OAAO,EAAE;AACtC,UAAM,UAAU,OAAO,UAAU;AACjC,UAAM,gBAAgB,IAAI,KAAK,KAAK;AACpC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS,OAAO,IAAI,IAAI,IAAI;AAAA,QAC5B,eAAW,cAAG,uBAAuB,SAAS;AAAA,QAC9C,MAAK;AAAA,QACL,cAAY,GAAG,GAAG;AAAA,QAElB;AAAA,sDAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAG,QAAQ,MAAK,QAAO,aAAa,QAAQ,WAAU,iBAAgB;AAAA,UAC1G;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,OAAO;AAAA,cACX,IAAI,OAAO;AAAA,cACX,GAAG;AAAA,cACH,MAAK;AAAA,cACL,aAAa;AAAA,cACb,eAAc;AAAA,cACd,QAAQ;AAAA,cACR,iBAAiB;AAAA,cACjB,kBAAkB,iBAAiB,IAAI,MAAM;AAAA;AAAA,UAC/C;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,cAAG,wDAAwD,SAAS;AAAA,MAC/E,MAAK;AAAA,MACL,iBAAe;AAAA,MACf,iBAAe;AAAA,MACf,iBAAe;AAAA,MAEf,sDAAC,SAAI,WAAU,0CAAyC,OAAO,EAAE,OAAO,GAAG,GAAG,KAAK,iBAAiB,WAAW,GAAG;AAAA;AAAA,EACpH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface XpProgressProps {
|
|
4
|
+
totalXp: number;
|
|
5
|
+
/** XP required to reach the current level. */
|
|
6
|
+
levelXp: number;
|
|
7
|
+
/** XP required for the next level; null at max level (renders full). */
|
|
8
|
+
nextLevelXp: number | null;
|
|
9
|
+
badgeColor: string;
|
|
10
|
+
variant?: "bar" | "ring";
|
|
11
|
+
/** Ring diameter in px (ring variant only). */
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/** XP progress toward the next level, as a rounded bar or an SVG ring. */
|
|
16
|
+
declare function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant, size, className }: XpProgressProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { XpProgress, type XpProgressProps };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface XpProgressProps {
|
|
4
|
+
totalXp: number;
|
|
5
|
+
/** XP required to reach the current level. */
|
|
6
|
+
levelXp: number;
|
|
7
|
+
/** XP required for the next level; null at max level (renders full). */
|
|
8
|
+
nextLevelXp: number | null;
|
|
9
|
+
badgeColor: string;
|
|
10
|
+
variant?: "bar" | "ring";
|
|
11
|
+
/** Ring diameter in px (ring variant only). */
|
|
12
|
+
size?: number;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/** XP progress toward the next level, as a rounded bar or an SVG ring. */
|
|
16
|
+
declare function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant, size, className }: XpProgressProps): react_jsx_runtime.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { XpProgress, type XpProgressProps };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
function progressPct({ totalXp, levelXp, nextLevelXp }) {
|
|
4
|
+
if (nextLevelXp === null || nextLevelXp <= levelXp) return 100;
|
|
5
|
+
return Math.min(100, Math.max(0, Math.round((totalXp - levelXp) / (nextLevelXp - levelXp) * 100)));
|
|
6
|
+
}
|
|
7
|
+
function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant = "bar", size = 40, className }) {
|
|
8
|
+
const pct = progressPct({ totalXp, levelXp, nextLevelXp });
|
|
9
|
+
if (variant === "ring") {
|
|
10
|
+
const stroke = Math.max(2.5, size / 12);
|
|
11
|
+
const radius = (size - stroke) / 2;
|
|
12
|
+
const circumference = 2 * Math.PI * radius;
|
|
13
|
+
return /* @__PURE__ */ jsxs(
|
|
14
|
+
"svg",
|
|
15
|
+
{
|
|
16
|
+
width: size,
|
|
17
|
+
height: size,
|
|
18
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
19
|
+
className: cn("shrink-0 -rotate-90", className),
|
|
20
|
+
role: "img",
|
|
21
|
+
"aria-label": `${pct}% toward the next level`,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r: radius, fill: "none", strokeWidth: stroke, className: "stroke-border" }),
|
|
24
|
+
/* @__PURE__ */ jsx(
|
|
25
|
+
"circle",
|
|
26
|
+
{
|
|
27
|
+
cx: size / 2,
|
|
28
|
+
cy: size / 2,
|
|
29
|
+
r: radius,
|
|
30
|
+
fill: "none",
|
|
31
|
+
strokeWidth: stroke,
|
|
32
|
+
strokeLinecap: "round",
|
|
33
|
+
stroke: badgeColor,
|
|
34
|
+
strokeDasharray: circumference,
|
|
35
|
+
strokeDashoffset: circumference * (1 - pct / 100)
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return /* @__PURE__ */ jsx(
|
|
43
|
+
"div",
|
|
44
|
+
{
|
|
45
|
+
className: cn("h-2 w-full overflow-hidden rounded-full bg-border/60", className),
|
|
46
|
+
role: "progressbar",
|
|
47
|
+
"aria-valuenow": pct,
|
|
48
|
+
"aria-valuemin": 0,
|
|
49
|
+
"aria-valuemax": 100,
|
|
50
|
+
children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-full transition-[width]", style: { width: `${pct}%`, backgroundColor: badgeColor } })
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
XpProgress
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=xp-progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/xp-progress.tsx"],"sourcesContent":["import { cn } from \"../../utils/cn.js\";\n\nexport interface XpProgressProps {\n totalXp: number;\n /** XP required to reach the current level. */\n levelXp: number;\n /** XP required for the next level; null at max level (renders full). */\n nextLevelXp: number | null;\n badgeColor: string;\n variant?: \"bar\" | \"ring\";\n /** Ring diameter in px (ring variant only). */\n size?: number;\n className?: string;\n}\n\nfunction progressPct({ totalXp, levelXp, nextLevelXp }: Pick<XpProgressProps, \"totalXp\" | \"levelXp\" | \"nextLevelXp\">): number {\n if (nextLevelXp === null || nextLevelXp <= levelXp) return 100;\n return Math.min(100, Math.max(0, Math.round(((totalXp - levelXp) / (nextLevelXp - levelXp)) * 100)));\n}\n\n/** XP progress toward the next level, as a rounded bar or an SVG ring. */\nexport function XpProgress({ totalXp, levelXp, nextLevelXp, badgeColor, variant = \"bar\", size = 40, className }: XpProgressProps) {\n const pct = progressPct({ totalXp, levelXp, nextLevelXp });\n\n if (variant === \"ring\") {\n const stroke = Math.max(2.5, size / 12);\n const radius = (size - stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n className={cn(\"shrink-0 -rotate-90\", className)}\n role=\"img\"\n aria-label={`${pct}% toward the next level`}\n >\n <circle cx={size / 2} cy={size / 2} r={radius} fill=\"none\" strokeWidth={stroke} className=\"stroke-border\" />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n stroke={badgeColor}\n strokeDasharray={circumference}\n strokeDashoffset={circumference * (1 - pct / 100)}\n />\n </svg>\n );\n }\n\n return (\n <div\n className={cn(\"h-2 w-full overflow-hidden rounded-full bg-border/60\", className)}\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div className=\"h-full rounded-full transition-[width]\" style={{ width: `${pct}%`, backgroundColor: badgeColor }} />\n </div>\n );\n}\n"],"mappings":"AA6BM,SAQE,KARF;AA7BN,SAAS,UAAU;AAenB,SAAS,YAAY,EAAE,SAAS,SAAS,YAAY,GAAyE;AAC5H,MAAI,gBAAgB,QAAQ,eAAe,QAAS,QAAO;AAC3D,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,OAAQ,UAAU,YAAY,cAAc,WAAY,GAAG,CAAC,CAAC;AACrG;AAGO,SAAS,WAAW,EAAE,SAAS,SAAS,aAAa,YAAY,UAAU,OAAO,OAAO,IAAI,UAAU,GAAoB;AAChI,QAAM,MAAM,YAAY,EAAE,SAAS,SAAS,YAAY,CAAC;AAEzD,MAAI,YAAY,QAAQ;AACtB,UAAM,SAAS,KAAK,IAAI,KAAK,OAAO,EAAE;AACtC,UAAM,UAAU,OAAO,UAAU;AACjC,UAAM,gBAAgB,IAAI,KAAK,KAAK;AACpC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS,OAAO,IAAI,IAAI,IAAI;AAAA,QAC5B,WAAW,GAAG,uBAAuB,SAAS;AAAA,QAC9C,MAAK;AAAA,QACL,cAAY,GAAG,GAAG;AAAA,QAElB;AAAA,8BAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAG,QAAQ,MAAK,QAAO,aAAa,QAAQ,WAAU,iBAAgB;AAAA,UAC1G;AAAA,YAAC;AAAA;AAAA,cACC,IAAI,OAAO;AAAA,cACX,IAAI,OAAO;AAAA,cACX,GAAG;AAAA,cACH,MAAK;AAAA,cACL,aAAa;AAAA,cACb,eAAc;AAAA,cACd,QAAQ;AAAA,cACR,iBAAiB;AAAA,cACjB,kBAAkB,iBAAiB,IAAI,MAAM;AAAA;AAAA,UAC/C;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,wDAAwD,SAAS;AAAA,MAC/E,MAAK;AAAA,MACL,iBAAe;AAAA,MACf,iBAAe;AAAA,MACf,iBAAe;AAAA,MAEf,8BAAC,SAAI,WAAU,0CAAyC,OAAO,EAAE,OAAO,GAAG,GAAG,KAAK,iBAAiB,WAAW,GAAG;AAAA;AAAA,EACpH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var xp_toast_content_exports = {};
|
|
20
|
+
__export(xp_toast_content_exports, {
|
|
21
|
+
XpToastContent: () => XpToastContent
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(xp_toast_content_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
function XpToastContent({ xp, label, color = "#8b5cf6" }) {
|
|
26
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2.5", children: [
|
|
27
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
28
|
+
"span",
|
|
29
|
+
{
|
|
30
|
+
className: "flex h-8 shrink-0 items-center rounded-full border px-2.5 text-sm font-black tabular-nums",
|
|
31
|
+
style: { borderColor: `${color}60`, backgroundColor: `${color}18`, color },
|
|
32
|
+
children: [
|
|
33
|
+
"+",
|
|
34
|
+
xp,
|
|
35
|
+
" XP"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0", children: [
|
|
40
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "truncate text-sm font-semibold", children: label }),
|
|
41
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground", children: "Counts toward your score soon" })
|
|
42
|
+
] })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
46
|
+
0 && (module.exports = {
|
|
47
|
+
XpToastContent
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=xp-toast-content.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/xp-toast-content.tsx"],"sourcesContent":["export interface XpToastContentProps {\n xp: number;\n /** The action's configured label, e.g. \"Mint an IP asset\". */\n label: string;\n color?: string;\n}\n\n/** Toast body for optimistic XP feedback: \"+20 XP · Mint an IP asset\".\n * Scores recompute on a schedule, so this shows the action's configured\n * value — the caller must never present it as a live balance. */\nexport function XpToastContent({ xp, label, color = \"#8b5cf6\" }: XpToastContentProps) {\n return (\n <div className=\"flex items-center gap-2.5\">\n <span\n className=\"flex h-8 shrink-0 items-center rounded-full border px-2.5 text-sm font-black tabular-nums\"\n style={{ borderColor: `${color}60`, backgroundColor: `${color}18`, color }}\n >\n +{xp} XP\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold\">{label}</p>\n <p className=\"text-xs text-muted-foreground\">Counts toward your score soon</p>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaM;AAHC,SAAS,eAAe,EAAE,IAAI,OAAO,QAAQ,UAAU,GAAwB;AACpF,SACE,6CAAC,SAAI,WAAU,6BACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,GAAG,KAAK,MAAM,iBAAiB,GAAG,KAAK,MAAM,MAAM;AAAA,QAC1E;AAAA;AAAA,UACG;AAAA,UAAG;AAAA;AAAA;AAAA,IACP;AAAA,IACA,6CAAC,SAAI,WAAU,WACb;AAAA,kDAAC,OAAE,WAAU,kCAAkC,iBAAM;AAAA,MACrD,4CAAC,OAAE,WAAU,iCAAgC,2CAA6B;AAAA,OAC5E;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface XpToastContentProps {
|
|
4
|
+
xp: number;
|
|
5
|
+
/** The action's configured label, e.g. "Mint an IP asset". */
|
|
6
|
+
label: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Toast body for optimistic XP feedback: "+20 XP · Mint an IP asset".
|
|
10
|
+
* Scores recompute on a schedule, so this shows the action's configured
|
|
11
|
+
* value — the caller must never present it as a live balance. */
|
|
12
|
+
declare function XpToastContent({ xp, label, color }: XpToastContentProps): react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
export { XpToastContent, type XpToastContentProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface XpToastContentProps {
|
|
4
|
+
xp: number;
|
|
5
|
+
/** The action's configured label, e.g. "Mint an IP asset". */
|
|
6
|
+
label: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Toast body for optimistic XP feedback: "+20 XP · Mint an IP asset".
|
|
10
|
+
* Scores recompute on a schedule, so this shows the action's configured
|
|
11
|
+
* value — the caller must never present it as a live balance. */
|
|
12
|
+
declare function XpToastContent({ xp, label, color }: XpToastContentProps): react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
export { XpToastContent, type XpToastContentProps };
|