@medialane/ui 0.36.0 → 0.37.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/load-more-sentinel.cjs +54 -0
- package/dist/components/load-more-sentinel.cjs.map +1 -0
- package/dist/components/load-more-sentinel.d.cts +17 -0
- package/dist/components/load-more-sentinel.d.ts +17 -0
- package/dist/components/load-more-sentinel.js +30 -0
- package/dist/components/load-more-sentinel.js.map +1 -0
- 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.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -128
- package/dist/index.d.ts +10 -128
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
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 load_more_sentinel_exports = {};
|
|
21
|
+
__export(load_more_sentinel_exports, {
|
|
22
|
+
LoadMoreSentinel: () => LoadMoreSentinel
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(load_more_sentinel_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
function LoadMoreSentinel({
|
|
28
|
+
hasMore,
|
|
29
|
+
isLoading,
|
|
30
|
+
onLoadMore,
|
|
31
|
+
rootMargin = "400px"
|
|
32
|
+
}) {
|
|
33
|
+
const ref = (0, import_react.useRef)(null);
|
|
34
|
+
(0, import_react.useEffect)(() => {
|
|
35
|
+
if (!hasMore || isLoading) return;
|
|
36
|
+
const el = ref.current;
|
|
37
|
+
if (!el) return;
|
|
38
|
+
const observer = new IntersectionObserver(
|
|
39
|
+
([entry]) => {
|
|
40
|
+
if (entry.isIntersecting) onLoadMore();
|
|
41
|
+
},
|
|
42
|
+
{ rootMargin }
|
|
43
|
+
);
|
|
44
|
+
observer.observe(el);
|
|
45
|
+
return () => observer.disconnect();
|
|
46
|
+
}, [hasMore, isLoading, rootMargin, onLoadMore]);
|
|
47
|
+
if (!hasMore) return null;
|
|
48
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, "aria-hidden": true, className: "h-px w-full" });
|
|
49
|
+
}
|
|
50
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
51
|
+
0 && (module.exports = {
|
|
52
|
+
LoadMoreSentinel
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=load-more-sentinel.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/load-more-sentinel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef } from \"react\";\n\nexport interface LoadMoreSentinelProps {\n hasMore: boolean;\n isLoading: boolean;\n onLoadMore: () => void;\n rootMargin?: string;\n}\n\n/**\n * Invisible trigger that calls `onLoadMore` when scrolled near the viewport.\n * Renders nothing once `hasMore` is false. Skips firing while `isLoading` is\n * true so callers can pass their existing \"currently fetching\" flag straight\n * through with no extra guard logic.\n */\nexport function LoadMoreSentinel({\n hasMore,\n isLoading,\n onLoadMore,\n rootMargin = \"400px\",\n}: LoadMoreSentinelProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!hasMore || isLoading) return;\n const el = ref.current;\n if (!el) return;\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) onLoadMore();\n },\n { rootMargin }\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [hasMore, isLoading, rootMargin, onLoadMore]);\n\n if (!hasMore) return null;\n return <div ref={ref} aria-hidden className=\"h-px w-full\" />;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyCS;AAvCT,mBAAkC;AAe3B,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAA0B;AACxB,QAAM,UAAM,qBAAuB,IAAI;AAEvC,8BAAU,MAAM;AACd,QAAI,CAAC,WAAW,UAAW;AAC3B,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AAET,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,CAAC,KAAK,MAAM;AACX,YAAI,MAAM,eAAgB,YAAW;AAAA,MACvC;AAAA,MACA,EAAE,WAAW;AAAA,IACf;AACA,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,SAAS,WAAW,YAAY,UAAU,CAAC;AAE/C,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,4CAAC,SAAI,KAAU,eAAW,MAAC,WAAU,eAAc;AAC5D;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LoadMoreSentinelProps {
|
|
4
|
+
hasMore: boolean;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
onLoadMore: () => void;
|
|
7
|
+
rootMargin?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Invisible trigger that calls `onLoadMore` when scrolled near the viewport.
|
|
11
|
+
* Renders nothing once `hasMore` is false. Skips firing while `isLoading` is
|
|
12
|
+
* true so callers can pass their existing "currently fetching" flag straight
|
|
13
|
+
* through with no extra guard logic.
|
|
14
|
+
*/
|
|
15
|
+
declare function LoadMoreSentinel({ hasMore, isLoading, onLoadMore, rootMargin, }: LoadMoreSentinelProps): react_jsx_runtime.JSX.Element | null;
|
|
16
|
+
|
|
17
|
+
export { LoadMoreSentinel, type LoadMoreSentinelProps };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LoadMoreSentinelProps {
|
|
4
|
+
hasMore: boolean;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
onLoadMore: () => void;
|
|
7
|
+
rootMargin?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Invisible trigger that calls `onLoadMore` when scrolled near the viewport.
|
|
11
|
+
* Renders nothing once `hasMore` is false. Skips firing while `isLoading` is
|
|
12
|
+
* true so callers can pass their existing "currently fetching" flag straight
|
|
13
|
+
* through with no extra guard logic.
|
|
14
|
+
*/
|
|
15
|
+
declare function LoadMoreSentinel({ hasMore, isLoading, onLoadMore, rootMargin, }: LoadMoreSentinelProps): react_jsx_runtime.JSX.Element | null;
|
|
16
|
+
|
|
17
|
+
export { LoadMoreSentinel, type LoadMoreSentinelProps };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
function LoadMoreSentinel({
|
|
5
|
+
hasMore,
|
|
6
|
+
isLoading,
|
|
7
|
+
onLoadMore,
|
|
8
|
+
rootMargin = "400px"
|
|
9
|
+
}) {
|
|
10
|
+
const ref = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!hasMore || isLoading) return;
|
|
13
|
+
const el = ref.current;
|
|
14
|
+
if (!el) return;
|
|
15
|
+
const observer = new IntersectionObserver(
|
|
16
|
+
([entry]) => {
|
|
17
|
+
if (entry.isIntersecting) onLoadMore();
|
|
18
|
+
},
|
|
19
|
+
{ rootMargin }
|
|
20
|
+
);
|
|
21
|
+
observer.observe(el);
|
|
22
|
+
return () => observer.disconnect();
|
|
23
|
+
}, [hasMore, isLoading, rootMargin, onLoadMore]);
|
|
24
|
+
if (!hasMore) return null;
|
|
25
|
+
return /* @__PURE__ */ jsx("div", { ref, "aria-hidden": true, className: "h-px w-full" });
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
LoadMoreSentinel
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=load-more-sentinel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/load-more-sentinel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef } from \"react\";\n\nexport interface LoadMoreSentinelProps {\n hasMore: boolean;\n isLoading: boolean;\n onLoadMore: () => void;\n rootMargin?: string;\n}\n\n/**\n * Invisible trigger that calls `onLoadMore` when scrolled near the viewport.\n * Renders nothing once `hasMore` is false. Skips firing while `isLoading` is\n * true so callers can pass their existing \"currently fetching\" flag straight\n * through with no extra guard logic.\n */\nexport function LoadMoreSentinel({\n hasMore,\n isLoading,\n onLoadMore,\n rootMargin = \"400px\",\n}: LoadMoreSentinelProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!hasMore || isLoading) return;\n const el = ref.current;\n if (!el) return;\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) onLoadMore();\n },\n { rootMargin }\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [hasMore, isLoading, rootMargin, onLoadMore]);\n\n if (!hasMore) return null;\n return <div ref={ref} aria-hidden className=\"h-px w-full\" />;\n}\n"],"mappings":";AAyCS;AAvCT,SAAS,WAAW,cAAc;AAe3B,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAA0B;AACxB,QAAM,MAAM,OAAuB,IAAI;AAEvC,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,UAAW;AAC3B,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AAET,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,CAAC,KAAK,MAAM;AACX,YAAI,MAAM,eAAgB,YAAW;AAAA,MACvC;AAAA,MACA,EAAE,WAAW;AAAA,IACf;AACA,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,SAAS,WAAW,YAAY,UAAU,CAAC;AAE/C,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,oBAAC,SAAI,KAAU,eAAW,MAAC,WAAU,eAAc;AAC5D;","names":[]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var badge_shelf_exports = {};
|
|
31
|
+
__export(badge_shelf_exports, {
|
|
32
|
+
BadgeShelf: () => BadgeShelf
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(badge_shelf_exports);
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var import_react = __toESM(require("react"), 1);
|
|
37
|
+
var import_cn = require("../../utils/cn.js");
|
|
38
|
+
const iconCache = /* @__PURE__ */ new Map();
|
|
39
|
+
function BadgeIcon({ name, color, className }) {
|
|
40
|
+
const [Icon, setIcon] = import_react.default.useState(
|
|
41
|
+
() => iconCache.get(name) ?? null
|
|
42
|
+
);
|
|
43
|
+
import_react.default.useEffect(() => {
|
|
44
|
+
if (iconCache.has(name)) {
|
|
45
|
+
setIcon(() => iconCache.get(name));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
import("lucide-react").then((mod) => {
|
|
49
|
+
const C = mod[name];
|
|
50
|
+
if (C) {
|
|
51
|
+
iconCache.set(name, C);
|
|
52
|
+
setIcon(() => C);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}, [name]);
|
|
56
|
+
if (!Icon) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("rounded-full", className), style: { backgroundColor: color } });
|
|
57
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className, style: { color } });
|
|
58
|
+
}
|
|
59
|
+
function BadgeShelf({ badges, earnedKeys, showLocked = false, className }) {
|
|
60
|
+
const earned = earnedKeys ? new Set(earnedKeys) : null;
|
|
61
|
+
const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));
|
|
62
|
+
if (visible.length === 0) return null;
|
|
63
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("flex flex-wrap gap-2", className), children: visible.map((badge) => {
|
|
64
|
+
const isLocked = earned ? !earned.has(badge.key) : false;
|
|
65
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
title: isLocked ? `${badge.description} \u2014 keep going to earn this` : badge.description,
|
|
69
|
+
className: (0, import_cn.cn)(
|
|
70
|
+
"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5",
|
|
71
|
+
isLocked && "opacity-45 grayscale"
|
|
72
|
+
),
|
|
73
|
+
style: {
|
|
74
|
+
borderColor: `${badge.color}60`,
|
|
75
|
+
backgroundColor: `${badge.color}14`
|
|
76
|
+
},
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(BadgeIcon, { name: badge.icon, color: badge.color, className: "h-3.5 w-3.5 shrink-0" }),
|
|
79
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-semibold", style: { color: badge.color }, children: badge.name })
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
badge.key
|
|
83
|
+
);
|
|
84
|
+
}) });
|
|
85
|
+
}
|
|
86
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
87
|
+
0 && (module.exports = {
|
|
88
|
+
BadgeShelf
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=badge-shelf.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nfunction BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CoB;AA7CpB,mBAAkB;AAElB,gBAAmB;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAEpE,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AAClG,QAAM,CAAC,MAAM,OAAO,IAAI,aAAAA,QAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,eAAAA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,4CAAC,UAAK,eAAW,cAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,4CAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,4CAAC,SAAI,eAAW,cAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,eAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,sDAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,4CAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":["React"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface BadgeShelfBadge {
|
|
4
|
+
key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
icon: string;
|
|
8
|
+
color: string;
|
|
9
|
+
category: string;
|
|
10
|
+
}
|
|
11
|
+
interface BadgeShelfProps {
|
|
12
|
+
/** The badges to render — the earned set, or the full catalog with `earnedKeys`. */
|
|
13
|
+
badges: BadgeShelfBadge[];
|
|
14
|
+
/** When set, badges outside this set render locked (grayscale, reduced opacity). */
|
|
15
|
+
earnedKeys?: string[];
|
|
16
|
+
/** Render locked badges too (requires `earnedKeys`); default hides them. */
|
|
17
|
+
showLocked?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Badge chips with native tooltips. Earned badges render in their color;
|
|
21
|
+
* locked ones (present in `badges` but not `earnedKeys`) render muted. */
|
|
22
|
+
declare function BadgeShelf({ badges, earnedKeys, showLocked, className }: BadgeShelfProps): react_jsx_runtime.JSX.Element | null;
|
|
23
|
+
|
|
24
|
+
export { BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface BadgeShelfBadge {
|
|
4
|
+
key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
icon: string;
|
|
8
|
+
color: string;
|
|
9
|
+
category: string;
|
|
10
|
+
}
|
|
11
|
+
interface BadgeShelfProps {
|
|
12
|
+
/** The badges to render — the earned set, or the full catalog with `earnedKeys`. */
|
|
13
|
+
badges: BadgeShelfBadge[];
|
|
14
|
+
/** When set, badges outside this set render locked (grayscale, reduced opacity). */
|
|
15
|
+
earnedKeys?: string[];
|
|
16
|
+
/** Render locked badges too (requires `earnedKeys`); default hides them. */
|
|
17
|
+
showLocked?: boolean;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Badge chips with native tooltips. Earned badges render in their color;
|
|
21
|
+
* locked ones (present in `badges` but not `earnedKeys`) render muted. */
|
|
22
|
+
declare function BadgeShelf({ badges, earnedKeys, showLocked, className }: BadgeShelfProps): react_jsx_runtime.JSX.Element | null;
|
|
23
|
+
|
|
24
|
+
export { BadgeShelf, type BadgeShelfBadge, type BadgeShelfProps };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { cn } from "../../utils/cn.js";
|
|
5
|
+
const iconCache = /* @__PURE__ */ new Map();
|
|
6
|
+
function BadgeIcon({ name, color, className }) {
|
|
7
|
+
const [Icon, setIcon] = React.useState(
|
|
8
|
+
() => iconCache.get(name) ?? null
|
|
9
|
+
);
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
if (iconCache.has(name)) {
|
|
12
|
+
setIcon(() => iconCache.get(name));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
import("lucide-react").then((mod) => {
|
|
16
|
+
const C = mod[name];
|
|
17
|
+
if (C) {
|
|
18
|
+
iconCache.set(name, C);
|
|
19
|
+
setIcon(() => C);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}, [name]);
|
|
23
|
+
if (!Icon) return /* @__PURE__ */ jsx("span", { className: cn("rounded-full", className), style: { backgroundColor: color } });
|
|
24
|
+
return /* @__PURE__ */ jsx(Icon, { className, style: { color } });
|
|
25
|
+
}
|
|
26
|
+
function BadgeShelf({ badges, earnedKeys, showLocked = false, className }) {
|
|
27
|
+
const earned = earnedKeys ? new Set(earnedKeys) : null;
|
|
28
|
+
const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));
|
|
29
|
+
if (visible.length === 0) return null;
|
|
30
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap gap-2", className), children: visible.map((badge) => {
|
|
31
|
+
const isLocked = earned ? !earned.has(badge.key) : false;
|
|
32
|
+
return /* @__PURE__ */ jsxs(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
title: isLocked ? `${badge.description} \u2014 keep going to earn this` : badge.description,
|
|
36
|
+
className: cn(
|
|
37
|
+
"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5",
|
|
38
|
+
isLocked && "opacity-45 grayscale"
|
|
39
|
+
),
|
|
40
|
+
style: {
|
|
41
|
+
borderColor: `${badge.color}60`,
|
|
42
|
+
backgroundColor: `${badge.color}14`
|
|
43
|
+
},
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx(BadgeIcon, { name: badge.icon, color: badge.color, className: "h-3.5 w-3.5 shrink-0" }),
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", style: { color: badge.color }, children: badge.name })
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
badge.key
|
|
50
|
+
);
|
|
51
|
+
}) });
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
BadgeShelf
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=badge-shelf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/badge-shelf.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\nimport type { LucideProps } from \"lucide-react\";\nimport { cn } from \"../../utils/cn.js\";\n\nexport interface BadgeShelfBadge {\n key: string;\n name: string;\n description: string;\n icon: string;\n color: string;\n category: string;\n}\n\nexport interface BadgeShelfProps {\n /** The badges to render — the earned set, or the full catalog with `earnedKeys`. */\n badges: BadgeShelfBadge[];\n /** When set, badges outside this set render locked (grayscale, reduced opacity). */\n earnedKeys?: string[];\n /** Render locked badges too (requires `earnedKeys`); default hides them. */\n showLocked?: boolean;\n className?: string;\n}\n\n// Lazily resolve lucide icons by name at runtime (icon names come from the API).\nconst iconCache = new Map<string, React.ComponentType<LucideProps>>();\n\nfunction BadgeIcon({ name, color, className }: { name: string; color: string; className?: string }) {\n const [Icon, setIcon] = React.useState<React.ComponentType<LucideProps> | null>(\n () => iconCache.get(name) ?? null\n );\n\n React.useEffect(() => {\n if (iconCache.has(name)) {\n setIcon(() => iconCache.get(name)!);\n return;\n }\n import(\"lucide-react\").then((mod) => {\n const C = (mod as Record<string, unknown>)[name] as React.ComponentType<LucideProps> | undefined;\n if (C) {\n iconCache.set(name, C);\n setIcon(() => C);\n }\n });\n }, [name]);\n\n if (!Icon) return <span className={cn(\"rounded-full\", className)} style={{ backgroundColor: color }} />;\n return <Icon className={className} style={{ color }} />;\n}\n\n/** Badge chips with native tooltips. Earned badges render in their color;\n * locked ones (present in `badges` but not `earnedKeys`) render muted. */\nexport function BadgeShelf({ badges, earnedKeys, showLocked = false, className }: BadgeShelfProps) {\n const earned = earnedKeys ? new Set(earnedKeys) : null;\n const visible = badges.filter((b) => showLocked || !earned || earned.has(b.key));\n if (visible.length === 0) return null;\n\n return (\n <div className={cn(\"flex flex-wrap gap-2\", className)}>\n {visible.map((badge) => {\n const isLocked = earned ? !earned.has(badge.key) : false;\n return (\n <div\n key={badge.key}\n title={isLocked ? `${badge.description} — keep going to earn this` : badge.description}\n className={cn(\n \"flex h-7 select-none items-center gap-1.5 rounded-full border px-2.5\",\n isLocked && \"opacity-45 grayscale\"\n )}\n style={{\n borderColor: `${badge.color}60`,\n backgroundColor: `${badge.color}14`,\n }}\n >\n <BadgeIcon name={badge.icon} color={badge.color} className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"text-xs font-semibold\" style={{ color: badge.color }}>\n {badge.name}\n </span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AA+CoB,cAgBV,YAhBU;AA7CpB,OAAO,WAAW;AAElB,SAAS,UAAU;AAsBnB,MAAM,YAAY,oBAAI,IAA8C;AAEpE,SAAS,UAAU,EAAE,MAAM,OAAO,UAAU,GAAwD;AAClG,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM;AAAA,IAC5B,MAAM,UAAU,IAAI,IAAI,KAAK;AAAA,EAC/B;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,IAAI,IAAI,GAAG;AACvB,cAAQ,MAAM,UAAU,IAAI,IAAI,CAAE;AAClC;AAAA,IACF;AACA,WAAO,cAAc,EAAE,KAAK,CAAC,QAAQ;AACnC,YAAM,IAAK,IAAgC,IAAI;AAC/C,UAAI,GAAG;AACL,kBAAU,IAAI,MAAM,CAAC;AACrB,gBAAQ,MAAM,CAAC;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO,oBAAC,UAAK,WAAW,GAAG,gBAAgB,SAAS,GAAG,OAAO,EAAE,iBAAiB,MAAM,GAAG;AACrG,SAAO,oBAAC,QAAK,WAAsB,OAAO,EAAE,MAAM,GAAG;AACvD;AAIO,SAAS,WAAW,EAAE,QAAQ,YAAY,aAAa,OAAO,UAAU,GAAoB;AACjG,QAAM,SAAS,aAAa,IAAI,IAAI,UAAU,IAAI;AAClD,QAAM,UAAU,OAAO,OAAO,CAAC,MAAM,cAAc,CAAC,UAAU,OAAO,IAAI,EAAE,GAAG,CAAC;AAC/E,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,SACE,oBAAC,SAAI,WAAW,GAAG,wBAAwB,SAAS,GACjD,kBAAQ,IAAI,CAAC,UAAU;AACtB,UAAM,WAAW,SAAS,CAAC,OAAO,IAAI,MAAM,GAAG,IAAI;AACnD,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,OAAO,WAAW,GAAG,MAAM,WAAW,oCAA+B,MAAM;AAAA,QAC3E,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QACA,OAAO;AAAA,UACL,aAAa,GAAG,MAAM,KAAK;AAAA,UAC3B,iBAAiB,GAAG,MAAM,KAAK;AAAA,QACjC;AAAA,QAEA;AAAA,8BAAC,aAAU,MAAM,MAAM,MAAM,OAAO,MAAM,OAAO,WAAU,wBAAuB;AAAA,UAClF,oBAAC,UAAK,WAAU,yBAAwB,OAAO,EAAE,OAAO,MAAM,MAAM,GACjE,gBAAM,MACT;AAAA;AAAA;AAAA,MAdK,MAAM;AAAA,IAeb;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
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 leaderboard_table_exports = {};
|
|
20
|
+
__export(leaderboard_table_exports, {
|
|
21
|
+
LeaderboardTable: () => LeaderboardTable,
|
|
22
|
+
LeaderboardWidget: () => LeaderboardWidget
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(leaderboard_table_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_cn = require("../../utils/cn.js");
|
|
27
|
+
var import_address = require("../../utils/address.js");
|
|
28
|
+
var import_level_badge = require("./level-badge.js");
|
|
29
|
+
function rankAccent(rank) {
|
|
30
|
+
if (rank === 1) return "#f59e0b";
|
|
31
|
+
if (rank === 2) return "#94a3b8";
|
|
32
|
+
if (rank === 3) return "#b45309";
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function LeaderboardTable({ entries, highlightAddress, renderAddress, className }) {
|
|
36
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_cn.cn)("overflow-hidden rounded-xl border border-border", className), children: entries.map((e) => {
|
|
37
|
+
const accent = rankAccent(e.rank);
|
|
38
|
+
const isViewer = highlightAddress != null && e.address === highlightAddress;
|
|
39
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
40
|
+
"div",
|
|
41
|
+
{
|
|
42
|
+
className: (0, import_cn.cn)(
|
|
43
|
+
"flex items-center gap-3 border-b border-border/60 bg-card px-3 py-2.5 last:border-b-0 sm:px-4",
|
|
44
|
+
isViewer && "bg-primary/10"
|
|
45
|
+
),
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
48
|
+
"span",
|
|
49
|
+
{
|
|
50
|
+
className: "w-8 shrink-0 text-center text-sm font-black tabular-nums",
|
|
51
|
+
style: accent ? { color: accent } : void 0,
|
|
52
|
+
children: e.rank
|
|
53
|
+
}
|
|
54
|
+
),
|
|
55
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: [
|
|
56
|
+
renderAddress ? renderAddress(e.address) : (0, import_address.shortenAddress)(e.address),
|
|
57
|
+
isViewer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-1.5 text-xs text-muted-foreground", children: "(you)" })
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_level_badge.LevelBadge, { level: e.currentLevel, name: e.currentLevelName, badgeColor: e.badgeColor, size: "sm", className: "hidden sm:inline-flex" }),
|
|
60
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "shrink-0 text-sm font-semibold tabular-nums", children: [
|
|
61
|
+
e.totalXp.toLocaleString(),
|
|
62
|
+
" XP"
|
|
63
|
+
] })
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
e.address
|
|
67
|
+
);
|
|
68
|
+
}) });
|
|
69
|
+
}
|
|
70
|
+
function LeaderboardWidget({ entries, title = "Top Creators", href, renderAddress, className }) {
|
|
71
|
+
if (entries.length === 0) return null;
|
|
72
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: (0, import_cn.cn)("rounded-xl border border-border bg-card p-4 sm:p-5", className), children: [
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-3 flex items-center justify-between", children: [
|
|
74
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-base font-black", children: title }),
|
|
75
|
+
href && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, className: "text-xs font-semibold text-muted-foreground active:opacity-70", children: "View leaderboard \u2192" })
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "space-y-2.5", children: entries.map((e) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "flex items-center gap-2.5", children: [
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
79
|
+
"span",
|
|
80
|
+
{
|
|
81
|
+
className: "w-5 shrink-0 text-center text-sm font-black tabular-nums",
|
|
82
|
+
style: rankAccent(e.rank) ? { color: rankAccent(e.rank) } : void 0,
|
|
83
|
+
children: e.rank
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: renderAddress ? renderAddress(e.address) : (0, import_address.shortenAddress)(e.address) }),
|
|
87
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_level_badge.LevelBadge, { level: e.currentLevel, name: e.currentLevelName, badgeColor: e.badgeColor, size: "sm" })
|
|
88
|
+
] }, e.address)) })
|
|
89
|
+
] });
|
|
90
|
+
}
|
|
91
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
92
|
+
0 && (module.exports = {
|
|
93
|
+
LeaderboardTable,
|
|
94
|
+
LeaderboardWidget
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=leaderboard-table.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/leaderboard-table.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn.js\";\nimport { shortenAddress } from \"../../utils/address.js\";\nimport { LevelBadge } from \"./level-badge.js\";\n\nexport interface LeaderboardEntryLike {\n rank: number;\n address: string;\n publicId?: string | null;\n totalXp: number;\n currentLevel: number;\n currentLevelName: string;\n badgeColor: string;\n}\n\nexport interface LeaderboardTableProps {\n entries: LeaderboardEntryLike[];\n /** The viewer's address — its row gets highlighted. */\n highlightAddress?: string | null;\n /** Render the address cell (e.g. a profile link). Defaults to a shortened address. */\n renderAddress?: (address: string) => ReactNode;\n className?: string;\n}\n\nfunction rankAccent(rank: number): string | null {\n if (rank === 1) return \"#f59e0b\";\n if (rank === 2) return \"#94a3b8\";\n if (rank === 3) return \"#b45309\";\n return null;\n}\n\n/** Full leaderboard rows: rank, address, level chip, XP. */\nexport function LeaderboardTable({ entries, highlightAddress, renderAddress, className }: LeaderboardTableProps) {\n return (\n <div className={cn(\"overflow-hidden rounded-xl border border-border\", className)}>\n {entries.map((e) => {\n const accent = rankAccent(e.rank);\n const isViewer = highlightAddress != null && e.address === highlightAddress;\n return (\n <div\n key={e.address}\n className={cn(\n \"flex items-center gap-3 border-b border-border/60 bg-card px-3 py-2.5 last:border-b-0 sm:px-4\",\n isViewer && \"bg-primary/10\"\n )}\n >\n <span\n className=\"w-8 shrink-0 text-center text-sm font-black tabular-nums\"\n style={accent ? { color: accent } : undefined}\n >\n {e.rank}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-medium\">\n {renderAddress ? renderAddress(e.address) : shortenAddress(e.address)}\n {isViewer && <span className=\"ml-1.5 text-xs text-muted-foreground\">(you)</span>}\n </span>\n <LevelBadge level={e.currentLevel} name={e.currentLevelName} badgeColor={e.badgeColor} size=\"sm\" className=\"hidden sm:inline-flex\" />\n <span className=\"shrink-0 text-sm font-semibold tabular-nums\">{e.totalXp.toLocaleString()} XP</span>\n </div>\n );\n })}\n </div>\n );\n}\n\nexport interface LeaderboardWidgetProps {\n entries: LeaderboardEntryLike[];\n title?: string;\n /** Link to the full leaderboard (\"/rewards\"). */\n href?: string;\n renderAddress?: (address: string) => ReactNode;\n className?: string;\n}\n\n/** Compact top-N card for homepage/discover rails. */\nexport function LeaderboardWidget({ entries, title = \"Top Creators\", href, renderAddress, className }: LeaderboardWidgetProps) {\n if (entries.length === 0) return null;\n return (\n <section className={cn(\"rounded-xl border border-border bg-card p-4 sm:p-5\", className)}>\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-base font-black\">{title}</h2>\n {href && (\n <a href={href} className=\"text-xs font-semibold text-muted-foreground active:opacity-70\">\n View leaderboard →\n </a>\n )}\n </div>\n <ol className=\"space-y-2.5\">\n {entries.map((e) => (\n <li key={e.address} className=\"flex items-center gap-2.5\">\n <span\n className=\"w-5 shrink-0 text-center text-sm font-black tabular-nums\"\n style={rankAccent(e.rank) ? { color: rankAccent(e.rank)! } : undefined}\n >\n {e.rank}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-medium\">\n {renderAddress ? renderAddress(e.address) : shortenAddress(e.address)}\n </span>\n <LevelBadge level={e.currentLevel} name={e.currentLevelName} badgeColor={e.badgeColor} size=\"sm\" />\n </li>\n ))}\n </ol>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CY;AA7CZ,gBAAmB;AACnB,qBAA+B;AAC/B,yBAA2B;AAqB3B,SAAS,WAAW,MAA6B;AAC/C,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO;AACT;AAGO,SAAS,iBAAiB,EAAE,SAAS,kBAAkB,eAAe,UAAU,GAA0B;AAC/G,SACE,4CAAC,SAAI,eAAW,cAAG,mDAAmD,SAAS,GAC5E,kBAAQ,IAAI,CAAC,MAAM;AAClB,UAAM,SAAS,WAAW,EAAE,IAAI;AAChC,UAAM,WAAW,oBAAoB,QAAQ,EAAE,YAAY;AAC3D,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,eAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,SAAS,EAAE,OAAO,OAAO,IAAI;AAAA,cAEnC,YAAE;AAAA;AAAA,UACL;AAAA,UACA,6CAAC,UAAK,WAAU,+CACb;AAAA,4BAAgB,cAAc,EAAE,OAAO,QAAI,+BAAe,EAAE,OAAO;AAAA,YACnE,YAAY,4CAAC,UAAK,WAAU,wCAAuC,mBAAK;AAAA,aAC3E;AAAA,UACA,4CAAC,iCAAW,OAAO,EAAE,cAAc,MAAM,EAAE,kBAAkB,YAAY,EAAE,YAAY,MAAK,MAAK,WAAU,yBAAwB;AAAA,UACnI,6CAAC,UAAK,WAAU,+CAA+C;AAAA,cAAE,QAAQ,eAAe;AAAA,YAAE;AAAA,aAAG;AAAA;AAAA;AAAA,MAjBxF,EAAE;AAAA,IAkBT;AAAA,EAEJ,CAAC,GACH;AAEJ;AAYO,SAAS,kBAAkB,EAAE,SAAS,QAAQ,gBAAgB,MAAM,eAAe,UAAU,GAA2B;AAC7H,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SACE,6CAAC,aAAQ,eAAW,cAAG,sDAAsD,SAAS,GACpF;AAAA,iDAAC,SAAI,WAAU,0CACb;AAAA,kDAAC,QAAG,WAAU,wBAAwB,iBAAM;AAAA,MAC3C,QACC,4CAAC,OAAE,MAAY,WAAU,iEAAgE,qCAEzF;AAAA,OAEJ;AAAA,IACA,4CAAC,QAAG,WAAU,eACX,kBAAQ,IAAI,CAAC,MACZ,6CAAC,QAAmB,WAAU,6BAC5B;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,WAAW,EAAE,IAAI,IAAI,EAAE,OAAO,WAAW,EAAE,IAAI,EAAG,IAAI;AAAA,UAE5D,YAAE;AAAA;AAAA,MACL;AAAA,MACA,4CAAC,UAAK,WAAU,+CACb,0BAAgB,cAAc,EAAE,OAAO,QAAI,+BAAe,EAAE,OAAO,GACtE;AAAA,MACA,4CAAC,iCAAW,OAAO,EAAE,cAAc,MAAM,EAAE,kBAAkB,YAAY,EAAE,YAAY,MAAK,MAAK;AAAA,SAV1F,EAAE,OAWX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface LeaderboardEntryLike {
|
|
5
|
+
rank: number;
|
|
6
|
+
address: string;
|
|
7
|
+
publicId?: string | null;
|
|
8
|
+
totalXp: number;
|
|
9
|
+
currentLevel: number;
|
|
10
|
+
currentLevelName: string;
|
|
11
|
+
badgeColor: string;
|
|
12
|
+
}
|
|
13
|
+
interface LeaderboardTableProps {
|
|
14
|
+
entries: LeaderboardEntryLike[];
|
|
15
|
+
/** The viewer's address — its row gets highlighted. */
|
|
16
|
+
highlightAddress?: string | null;
|
|
17
|
+
/** Render the address cell (e.g. a profile link). Defaults to a shortened address. */
|
|
18
|
+
renderAddress?: (address: string) => ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Full leaderboard rows: rank, address, level chip, XP. */
|
|
22
|
+
declare function LeaderboardTable({ entries, highlightAddress, renderAddress, className }: LeaderboardTableProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
interface LeaderboardWidgetProps {
|
|
24
|
+
entries: LeaderboardEntryLike[];
|
|
25
|
+
title?: string;
|
|
26
|
+
/** Link to the full leaderboard ("/rewards"). */
|
|
27
|
+
href?: string;
|
|
28
|
+
renderAddress?: (address: string) => ReactNode;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Compact top-N card for homepage/discover rails. */
|
|
32
|
+
declare function LeaderboardWidget({ entries, title, href, renderAddress, className }: LeaderboardWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
33
|
+
|
|
34
|
+
export { type LeaderboardEntryLike, LeaderboardTable, type LeaderboardTableProps, LeaderboardWidget, type LeaderboardWidgetProps };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface LeaderboardEntryLike {
|
|
5
|
+
rank: number;
|
|
6
|
+
address: string;
|
|
7
|
+
publicId?: string | null;
|
|
8
|
+
totalXp: number;
|
|
9
|
+
currentLevel: number;
|
|
10
|
+
currentLevelName: string;
|
|
11
|
+
badgeColor: string;
|
|
12
|
+
}
|
|
13
|
+
interface LeaderboardTableProps {
|
|
14
|
+
entries: LeaderboardEntryLike[];
|
|
15
|
+
/** The viewer's address — its row gets highlighted. */
|
|
16
|
+
highlightAddress?: string | null;
|
|
17
|
+
/** Render the address cell (e.g. a profile link). Defaults to a shortened address. */
|
|
18
|
+
renderAddress?: (address: string) => ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Full leaderboard rows: rank, address, level chip, XP. */
|
|
22
|
+
declare function LeaderboardTable({ entries, highlightAddress, renderAddress, className }: LeaderboardTableProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
interface LeaderboardWidgetProps {
|
|
24
|
+
entries: LeaderboardEntryLike[];
|
|
25
|
+
title?: string;
|
|
26
|
+
/** Link to the full leaderboard ("/rewards"). */
|
|
27
|
+
href?: string;
|
|
28
|
+
renderAddress?: (address: string) => ReactNode;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Compact top-N card for homepage/discover rails. */
|
|
32
|
+
declare function LeaderboardWidget({ entries, title, href, renderAddress, className }: LeaderboardWidgetProps): react_jsx_runtime.JSX.Element | null;
|
|
33
|
+
|
|
34
|
+
export { type LeaderboardEntryLike, LeaderboardTable, type LeaderboardTableProps, LeaderboardWidget, type LeaderboardWidgetProps };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../utils/cn.js";
|
|
3
|
+
import { shortenAddress } from "../../utils/address.js";
|
|
4
|
+
import { LevelBadge } from "./level-badge.js";
|
|
5
|
+
function rankAccent(rank) {
|
|
6
|
+
if (rank === 1) return "#f59e0b";
|
|
7
|
+
if (rank === 2) return "#94a3b8";
|
|
8
|
+
if (rank === 3) return "#b45309";
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
function LeaderboardTable({ entries, highlightAddress, renderAddress, className }) {
|
|
12
|
+
return /* @__PURE__ */ jsx("div", { className: cn("overflow-hidden rounded-xl border border-border", className), children: entries.map((e) => {
|
|
13
|
+
const accent = rankAccent(e.rank);
|
|
14
|
+
const isViewer = highlightAddress != null && e.address === highlightAddress;
|
|
15
|
+
return /* @__PURE__ */ jsxs(
|
|
16
|
+
"div",
|
|
17
|
+
{
|
|
18
|
+
className: cn(
|
|
19
|
+
"flex items-center gap-3 border-b border-border/60 bg-card px-3 py-2.5 last:border-b-0 sm:px-4",
|
|
20
|
+
isViewer && "bg-primary/10"
|
|
21
|
+
),
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
"span",
|
|
25
|
+
{
|
|
26
|
+
className: "w-8 shrink-0 text-center text-sm font-black tabular-nums",
|
|
27
|
+
style: accent ? { color: accent } : void 0,
|
|
28
|
+
children: e.rank
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: [
|
|
32
|
+
renderAddress ? renderAddress(e.address) : shortenAddress(e.address),
|
|
33
|
+
isViewer && /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-xs text-muted-foreground", children: "(you)" })
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsx(LevelBadge, { level: e.currentLevel, name: e.currentLevelName, badgeColor: e.badgeColor, size: "sm", className: "hidden sm:inline-flex" }),
|
|
36
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 text-sm font-semibold tabular-nums", children: [
|
|
37
|
+
e.totalXp.toLocaleString(),
|
|
38
|
+
" XP"
|
|
39
|
+
] })
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
e.address
|
|
43
|
+
);
|
|
44
|
+
}) });
|
|
45
|
+
}
|
|
46
|
+
function LeaderboardWidget({ entries, title = "Top Creators", href, renderAddress, className }) {
|
|
47
|
+
if (entries.length === 0) return null;
|
|
48
|
+
return /* @__PURE__ */ jsxs("section", { className: cn("rounded-xl border border-border bg-card p-4 sm:p-5", className), children: [
|
|
49
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
|
|
50
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-black", children: title }),
|
|
51
|
+
href && /* @__PURE__ */ jsx("a", { href, className: "text-xs font-semibold text-muted-foreground active:opacity-70", children: "View leaderboard \u2192" })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsx("ol", { className: "space-y-2.5", children: entries.map((e) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
54
|
+
/* @__PURE__ */ jsx(
|
|
55
|
+
"span",
|
|
56
|
+
{
|
|
57
|
+
className: "w-5 shrink-0 text-center text-sm font-black tabular-nums",
|
|
58
|
+
style: rankAccent(e.rank) ? { color: rankAccent(e.rank) } : void 0,
|
|
59
|
+
children: e.rank
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: renderAddress ? renderAddress(e.address) : shortenAddress(e.address) }),
|
|
63
|
+
/* @__PURE__ */ jsx(LevelBadge, { level: e.currentLevel, name: e.currentLevelName, badgeColor: e.badgeColor, size: "sm" })
|
|
64
|
+
] }, e.address)) })
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
LeaderboardTable,
|
|
69
|
+
LeaderboardWidget
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=leaderboard-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/rewards/leaderboard-table.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../../utils/cn.js\";\nimport { shortenAddress } from \"../../utils/address.js\";\nimport { LevelBadge } from \"./level-badge.js\";\n\nexport interface LeaderboardEntryLike {\n rank: number;\n address: string;\n publicId?: string | null;\n totalXp: number;\n currentLevel: number;\n currentLevelName: string;\n badgeColor: string;\n}\n\nexport interface LeaderboardTableProps {\n entries: LeaderboardEntryLike[];\n /** The viewer's address — its row gets highlighted. */\n highlightAddress?: string | null;\n /** Render the address cell (e.g. a profile link). Defaults to a shortened address. */\n renderAddress?: (address: string) => ReactNode;\n className?: string;\n}\n\nfunction rankAccent(rank: number): string | null {\n if (rank === 1) return \"#f59e0b\";\n if (rank === 2) return \"#94a3b8\";\n if (rank === 3) return \"#b45309\";\n return null;\n}\n\n/** Full leaderboard rows: rank, address, level chip, XP. */\nexport function LeaderboardTable({ entries, highlightAddress, renderAddress, className }: LeaderboardTableProps) {\n return (\n <div className={cn(\"overflow-hidden rounded-xl border border-border\", className)}>\n {entries.map((e) => {\n const accent = rankAccent(e.rank);\n const isViewer = highlightAddress != null && e.address === highlightAddress;\n return (\n <div\n key={e.address}\n className={cn(\n \"flex items-center gap-3 border-b border-border/60 bg-card px-3 py-2.5 last:border-b-0 sm:px-4\",\n isViewer && \"bg-primary/10\"\n )}\n >\n <span\n className=\"w-8 shrink-0 text-center text-sm font-black tabular-nums\"\n style={accent ? { color: accent } : undefined}\n >\n {e.rank}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-medium\">\n {renderAddress ? renderAddress(e.address) : shortenAddress(e.address)}\n {isViewer && <span className=\"ml-1.5 text-xs text-muted-foreground\">(you)</span>}\n </span>\n <LevelBadge level={e.currentLevel} name={e.currentLevelName} badgeColor={e.badgeColor} size=\"sm\" className=\"hidden sm:inline-flex\" />\n <span className=\"shrink-0 text-sm font-semibold tabular-nums\">{e.totalXp.toLocaleString()} XP</span>\n </div>\n );\n })}\n </div>\n );\n}\n\nexport interface LeaderboardWidgetProps {\n entries: LeaderboardEntryLike[];\n title?: string;\n /** Link to the full leaderboard (\"/rewards\"). */\n href?: string;\n renderAddress?: (address: string) => ReactNode;\n className?: string;\n}\n\n/** Compact top-N card for homepage/discover rails. */\nexport function LeaderboardWidget({ entries, title = \"Top Creators\", href, renderAddress, className }: LeaderboardWidgetProps) {\n if (entries.length === 0) return null;\n return (\n <section className={cn(\"rounded-xl border border-border bg-card p-4 sm:p-5\", className)}>\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-base font-black\">{title}</h2>\n {href && (\n <a href={href} className=\"text-xs font-semibold text-muted-foreground active:opacity-70\">\n View leaderboard →\n </a>\n )}\n </div>\n <ol className=\"space-y-2.5\">\n {entries.map((e) => (\n <li key={e.address} className=\"flex items-center gap-2.5\">\n <span\n className=\"w-5 shrink-0 text-center text-sm font-black tabular-nums\"\n style={rankAccent(e.rank) ? { color: rankAccent(e.rank)! } : undefined}\n >\n {e.rank}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-sm font-medium\">\n {renderAddress ? renderAddress(e.address) : shortenAddress(e.address)}\n </span>\n <LevelBadge level={e.currentLevel} name={e.currentLevelName} badgeColor={e.badgeColor} size=\"sm\" />\n </li>\n ))}\n </ol>\n </section>\n );\n}\n"],"mappings":"AA8CY,cAMA,YANA;AA7CZ,SAAS,UAAU;AACnB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAqB3B,SAAS,WAAW,MAA6B;AAC/C,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO;AACT;AAGO,SAAS,iBAAiB,EAAE,SAAS,kBAAkB,eAAe,UAAU,GAA0B;AAC/G,SACE,oBAAC,SAAI,WAAW,GAAG,mDAAmD,SAAS,GAC5E,kBAAQ,IAAI,CAAC,MAAM;AAClB,UAAM,SAAS,WAAW,EAAE,IAAI;AAChC,UAAM,WAAW,oBAAoB,QAAQ,EAAE,YAAY;AAC3D,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,SAAS,EAAE,OAAO,OAAO,IAAI;AAAA,cAEnC,YAAE;AAAA;AAAA,UACL;AAAA,UACA,qBAAC,UAAK,WAAU,+CACb;AAAA,4BAAgB,cAAc,EAAE,OAAO,IAAI,eAAe,EAAE,OAAO;AAAA,YACnE,YAAY,oBAAC,UAAK,WAAU,wCAAuC,mBAAK;AAAA,aAC3E;AAAA,UACA,oBAAC,cAAW,OAAO,EAAE,cAAc,MAAM,EAAE,kBAAkB,YAAY,EAAE,YAAY,MAAK,MAAK,WAAU,yBAAwB;AAAA,UACnI,qBAAC,UAAK,WAAU,+CAA+C;AAAA,cAAE,QAAQ,eAAe;AAAA,YAAE;AAAA,aAAG;AAAA;AAAA;AAAA,MAjBxF,EAAE;AAAA,IAkBT;AAAA,EAEJ,CAAC,GACH;AAEJ;AAYO,SAAS,kBAAkB,EAAE,SAAS,QAAQ,gBAAgB,MAAM,eAAe,UAAU,GAA2B;AAC7H,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SACE,qBAAC,aAAQ,WAAW,GAAG,sDAAsD,SAAS,GACpF;AAAA,yBAAC,SAAI,WAAU,0CACb;AAAA,0BAAC,QAAG,WAAU,wBAAwB,iBAAM;AAAA,MAC3C,QACC,oBAAC,OAAE,MAAY,WAAU,iEAAgE,qCAEzF;AAAA,OAEJ;AAAA,IACA,oBAAC,QAAG,WAAU,eACX,kBAAQ,IAAI,CAAC,MACZ,qBAAC,QAAmB,WAAU,6BAC5B;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,WAAW,EAAE,IAAI,IAAI,EAAE,OAAO,WAAW,EAAE,IAAI,EAAG,IAAI;AAAA,UAE5D,YAAE;AAAA;AAAA,MACL;AAAA,MACA,oBAAC,UAAK,WAAU,+CACb,0BAAgB,cAAc,EAAE,OAAO,IAAI,eAAe,EAAE,OAAO,GACtE;AAAA,MACA,oBAAC,cAAW,OAAO,EAAE,cAAc,MAAM,EAAE,kBAAkB,YAAY,EAAE,YAAY,MAAK,MAAK;AAAA,SAV1F,EAAE,OAWX,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
|