@agg-build/ui 4.18.2 → 4.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +1 -0
  2. package/dist/{chunk-RFMA5ABT.mjs → chunk-GT3DCFIT.mjs} +489 -36
  3. package/dist/index.js +1070 -603
  4. package/dist/index.mjs +9 -1
  5. package/dist/pages.js +502 -35
  6. package/dist/pages.mjs +9 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/tailwind.css +1 -1
  9. package/dist/types/pages/index.d.mts +1 -0
  10. package/dist/types/pages/index.d.ts +1 -0
  11. package/dist/types/pages/leaderboard/components/leaderboard-header-row.d.mts +7 -0
  12. package/dist/types/pages/leaderboard/components/leaderboard-header-row.d.ts +7 -0
  13. package/dist/types/pages/leaderboard/components/leaderboard-row.d.mts +7 -0
  14. package/dist/types/pages/leaderboard/components/leaderboard-row.d.ts +7 -0
  15. package/dist/types/pages/leaderboard/components/leaderboard-skeleton.d.mts +3 -0
  16. package/dist/types/pages/leaderboard/components/leaderboard-skeleton.d.ts +3 -0
  17. package/dist/types/pages/leaderboard/components/segmented-control.d.mts +18 -0
  18. package/dist/types/pages/leaderboard/components/segmented-control.d.ts +18 -0
  19. package/dist/types/pages/leaderboard/index.d.mts +28 -0
  20. package/dist/types/pages/leaderboard/index.d.ts +28 -0
  21. package/dist/types/pages/leaderboard/leaderboard.constants.d.mts +8 -0
  22. package/dist/types/pages/leaderboard/leaderboard.constants.d.ts +8 -0
  23. package/dist/types/pages/leaderboard/leaderboard.types.d.mts +11 -0
  24. package/dist/types/pages/leaderboard/leaderboard.types.d.ts +11 -0
  25. package/dist/types/pages/user-profile/position-view-model.d.mts +2 -4
  26. package/dist/types/pages/user-profile/position-view-model.d.ts +2 -4
  27. package/dist/types/shared/pnl-format.d.mts +20 -0
  28. package/dist/types/shared/pnl-format.d.ts +20 -0
  29. package/package.json +3 -3
  30. /package/dist/types/{pages/user-profile/components → shared}/default-avatar.d.mts +0 -0
  31. /package/dist/types/{pages/user-profile/components → shared}/default-avatar.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -4,6 +4,10 @@ import {
4
4
  ConditionalWrapper,
5
5
  DefaultAvatar,
6
6
  HomePage,
7
+ LEADERBOARD_DEFAULT_METRIC,
8
+ LEADERBOARD_DEFAULT_PERIOD,
9
+ LEADERBOARD_METRICS,
10
+ LeaderboardPage,
7
11
  ManageBalancesModal,
8
12
  USER_PROFILE_TAB_ACTIVITY,
9
13
  USER_PROFILE_TAB_OPEN_ORDERS,
@@ -12,7 +16,7 @@ import {
12
16
  buildAggTxExplorerHref,
13
17
  formatShareAmount,
14
18
  useHomePageModals
15
- } from "./chunk-RFMA5ABT.mjs";
19
+ } from "./chunk-GT3DCFIT.mjs";
16
20
  import {
17
21
  EventList,
18
22
  EventListItem,
@@ -1066,6 +1070,10 @@ export {
1066
1070
  ImageIcon,
1067
1071
  InfoIcon,
1068
1072
  InlineAlert,
1073
+ LEADERBOARD_DEFAULT_METRIC,
1074
+ LEADERBOARD_DEFAULT_PERIOD,
1075
+ LEADERBOARD_METRICS,
1076
+ LeaderboardPage,
1069
1077
  LineChart,
1070
1078
  LinkAccountsIcon,
1071
1079
  LoadingIcon,
package/dist/pages.js CHANGED
@@ -32701,6 +32701,10 @@ __export(pages_exports, {
32701
32701
  EventOpenOrders: () => EventOpenOrders,
32702
32702
  EventOpenOrdersCard: () => EventOpenOrdersCard,
32703
32703
  HomePage: () => HomePage,
32704
+ LEADERBOARD_DEFAULT_METRIC: () => LEADERBOARD_DEFAULT_METRIC,
32705
+ LEADERBOARD_DEFAULT_PERIOD: () => LEADERBOARD_DEFAULT_PERIOD,
32706
+ LEADERBOARD_METRICS: () => LEADERBOARD_METRICS,
32707
+ LeaderboardPage: () => LeaderboardPage,
32704
32708
  ManageBalancesModal: () => ManageBalancesModal,
32705
32709
  USER_PROFILE_TAB_ACTIVITY: () => USER_PROFILE_TAB_ACTIVITY,
32706
32710
  USER_PROFILE_TAB_OPEN_ORDERS: () => USER_PROFILE_TAB_OPEN_ORDERS,
@@ -36774,24 +36778,58 @@ var USER_PROFILE_POSITION_FILTERS = [
36774
36778
  { value: "closed", label: "Closed" }
36775
36779
  ];
36776
36780
 
36777
- // src/pages/user-profile/position-view-model.ts
36778
- var defaultLabels2 = {
36779
- avgPrefix: "avg",
36780
- nowPrefix: "now",
36781
- finalPrefix: "final"
36782
- };
36783
- var missingLabel = "\u2014";
36781
+ // src/shared/pnl-format.ts
36782
+ var MISSING_VALUE_LABEL = "\u2014";
36784
36783
  var usdFormatter = new Intl.NumberFormat("en-US", {
36785
36784
  style: "currency",
36786
36785
  currency: "USD",
36787
36786
  minimumFractionDigits: 2,
36788
36787
  maximumFractionDigits: 2
36789
36788
  });
36789
+ var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
36790
+ var formatCurrency = (value, formatCurrencyOverride) => {
36791
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
36792
+ if (formatCurrencyOverride) return formatCurrencyOverride(value);
36793
+ return usdFormatter.format(value);
36794
+ };
36795
+ var NEGLIGIBLE_CURRENCY_THRESHOLD = 5e-3;
36796
+ var formatSignedCurrency = (value, formatCurrencyOverride, options = {}) => {
36797
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
36798
+ if (value === 0) return formatCurrency(0, formatCurrencyOverride);
36799
+ const sign = value > 0 ? "+" : "-";
36800
+ const magnitude = Math.abs(value);
36801
+ if (options.markNegligible && magnitude < NEGLIGIBLE_CURRENCY_THRESHOLD) {
36802
+ return `${sign}<${formatCurrency(0.01, formatCurrencyOverride)}`;
36803
+ }
36804
+ return `${sign}${formatCurrency(magnitude, formatCurrencyOverride)}`;
36805
+ };
36806
+ var formatCurrencyMarkingNegligible = (value, formatCurrencyOverride) => {
36807
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
36808
+ if (value !== 0 && Math.abs(value) < NEGLIGIBLE_CURRENCY_THRESHOLD) {
36809
+ return `<${formatCurrency(0.01, formatCurrencyOverride)}`;
36810
+ }
36811
+ return formatCurrency(value, formatCurrencyOverride);
36812
+ };
36813
+ var getPositionTone = (value) => {
36814
+ if (!isFiniteNumber(value) || value === 0) return "neutral";
36815
+ return value > 0 ? "positive" : "negative";
36816
+ };
36817
+ var toneClassName = (tone) => {
36818
+ if (tone === "positive") return "text-agg-success";
36819
+ if (tone === "negative") return "text-agg-error";
36820
+ return "text-agg-muted-foreground";
36821
+ };
36822
+
36823
+ // src/pages/user-profile/position-view-model.ts
36824
+ var defaultLabels2 = {
36825
+ avgPrefix: "avg",
36826
+ nowPrefix: "now",
36827
+ finalPrefix: "final"
36828
+ };
36790
36829
  var percentFormatter = new Intl.NumberFormat("en-US", {
36791
36830
  minimumFractionDigits: 0,
36792
36831
  maximumFractionDigits: 1
36793
36832
  });
36794
- var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
36795
36833
  var parseCurrencyLabel = (label2) => {
36796
36834
  if (!label2) return null;
36797
36835
  const normalized = label2.replace(/[$,\s]/g, "");
@@ -36812,23 +36850,13 @@ var parsePercentLabel = (label2) => {
36812
36850
  const parsed = Number(match[1].replace(/,/g, ""));
36813
36851
  return Number.isFinite(parsed) ? parsed : null;
36814
36852
  };
36815
- var formatCurrency = (value, formatCurrencyOverride) => {
36816
- if (!isFiniteNumber(value)) return missingLabel;
36817
- if (formatCurrencyOverride) return formatCurrencyOverride(value);
36818
- return usdFormatter.format(value);
36819
- };
36820
- var formatSignedCurrency = (value, formatCurrencyOverride) => {
36821
- if (!isFiniteNumber(value)) return missingLabel;
36822
- if (value === 0) return formatCurrency(0, formatCurrencyOverride);
36823
- return `${value > 0 ? "+" : "-"}${formatCurrency(Math.abs(value), formatCurrencyOverride)}`;
36824
- };
36825
36853
  var formatPriceCents2 = (value, formatPrice) => {
36826
- if (!isFiniteNumber(value)) return missingLabel;
36854
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
36827
36855
  if (formatPrice) return formatPrice(value);
36828
36856
  return `${Math.round(value * 100)}\xA2`;
36829
36857
  };
36830
36858
  var formatSignedPercent = (value) => {
36831
- if (!isFiniteNumber(value)) return missingLabel;
36859
+ if (!isFiniteNumber(value)) return MISSING_VALUE_LABEL;
36832
36860
  if (value === 0) return "0%";
36833
36861
  return `${value > 0 ? "+" : "-"}${percentFormatter.format(Math.abs(value))}%`;
36834
36862
  };
@@ -36916,10 +36944,6 @@ var getFinalPnlPercent = (position, pnlValue) => {
36916
36944
  }
36917
36945
  return null;
36918
36946
  };
36919
- var getPositionTone = (value) => {
36920
- if (!isFiniteNumber(value) || value === 0) return "neutral";
36921
- return value > 0 ? "positive" : "negative";
36922
- };
36923
36947
  var toPositionRowViewModel = (position, labels = defaultLabels2, formatters = {}) => {
36924
36948
  const { formatCurrency: currency, formatPrice: price } = formatters;
36925
36949
  const positionStatus = resolvePositionStatus(position);
@@ -36933,10 +36957,10 @@ var toPositionRowViewModel = (position, labels = defaultLabels2, formatters = {}
36933
36957
  position,
36934
36958
  positionStatus,
36935
36959
  bucket: resolvePositionBucket(position),
36936
- title: position.title || missingLabel,
36960
+ title: position.title || MISSING_VALUE_LABEL,
36937
36961
  thumbnailSrc: position.thumbnailSrc,
36938
- selectedOutcomeLabel: position.outcomeLabel || missingLabel,
36939
- resolutionLabel: position.resolutionLabel || position.outcomeLabel || missingLabel,
36962
+ selectedOutcomeLabel: position.outcomeLabel || MISSING_VALUE_LABEL,
36963
+ resolutionLabel: position.resolutionLabel || position.outcomeLabel || MISSING_VALUE_LABEL,
36940
36964
  venueShareBreakdown: position.venueShareBreakdown,
36941
36965
  totalTraded: {
36942
36966
  primaryLabel: formatCurrency(getTotalTradedValue(position), currency),
@@ -37573,11 +37597,6 @@ var import_jsx_runtime199 = require("react/jsx-runtime");
37573
37597
  var shouldUseNativeLinkNavigation3 = (event) => {
37574
37598
  return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button === 1;
37575
37599
  };
37576
- var toneTextClassName = (tone) => {
37577
- if (tone === "positive") return "text-agg-success";
37578
- if (tone === "negative") return "text-agg-error";
37579
- return "text-agg-muted-foreground";
37580
- };
37581
37600
  var OutcomePill = ({ label: label2 }) => /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("span", { className: "agg-position-outcome max-w-[120px] inline-flex items-center justify-center rounded-full bg-agg-secondary-hover px-4 py-[6px]", children: /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("span", { className: "whitespace-nowrap font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground truncate", children: label2 }) });
37582
37601
  var ResolutionPill = ({ label: label2 }) => /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("span", { className: "agg-position-resolution-pill inline-flex w-full items-center justify-center overflow-hidden rounded-full bg-agg-secondary-hover px-4 py-[6px] md:w-auto", children: /* @__PURE__ */ (0, import_jsx_runtime199.jsx)("span", { className: "truncate whitespace-nowrap font-agg-sans text-agg-sm leading-agg-5 font-agg-normal text-agg-foreground", children: label2 }) });
37583
37602
  var VenueShares = ({
@@ -37676,7 +37695,7 @@ var PositionValueCell = ({
37676
37695
  {
37677
37696
  className: cn(
37678
37697
  "font-agg-sans text-agg-sm leading-agg-5 font-agg-normal",
37679
- toneTextClassName(value.tone)
37698
+ toneClassName(value.tone)
37680
37699
  ),
37681
37700
  children: value.deltaLabel
37682
37701
  }
@@ -37689,7 +37708,7 @@ var PositionValueCell = ({
37689
37708
  {
37690
37709
  className: cn(
37691
37710
  "font-agg-sans text-agg-xs leading-agg-4 font-agg-normal",
37692
- toneTextClassName(value.tone)
37711
+ toneClassName(value.tone)
37693
37712
  ),
37694
37713
  children: value.percentLabel
37695
37714
  }
@@ -38614,7 +38633,7 @@ init_icon();
38614
38633
  init_tooltip();
38615
38634
  init_utils();
38616
38635
 
38617
- // src/pages/user-profile/components/default-avatar.tsx
38636
+ // src/shared/default-avatar.tsx
38618
38637
  init_utils();
38619
38638
  var import_jsx_runtime202 = require("react/jsx-runtime");
38620
38639
  var DefaultAvatar = ({ className }) => {
@@ -40013,6 +40032,450 @@ var UserProfilePage = ({
40013
40032
  };
40014
40033
  UserProfilePage.displayName = "UserProfilePage";
40015
40034
 
40035
+ // src/pages/leaderboard/index.tsx
40036
+ var import_hooks102 = require("@agg-build/hooks");
40037
+ var import_react69 = require("react");
40038
+ init_button();
40039
+ init_error_boundary();
40040
+ init_icon();
40041
+ init_state_message();
40042
+ init_utils();
40043
+
40044
+ // src/pages/leaderboard/components/leaderboard-header-row.tsx
40045
+ var import_hooks99 = require("@agg-build/hooks");
40046
+ init_utils();
40047
+
40048
+ // src/pages/leaderboard/leaderboard.constants.ts
40049
+ var LEADERBOARD_DEFAULT_PERIOD = "30d";
40050
+ var LEADERBOARD_DEFAULT_METRIC = "realizedPnl";
40051
+ var LEADERBOARD_METRICS = ["realizedPnl", "volume"];
40052
+ var LEADERBOARD_TOP_RANKS = 3;
40053
+ var LEADERBOARD_GRID_CLASS = "grid grid-cols-[36px_minmax(0,1fr)] grid-rows-[auto_auto] gap-x-3 gap-y-2 sm:grid-cols-[48px_minmax(0,1fr)_88px_128px_128px] sm:grid-rows-1 sm:gap-x-3 sm:gap-y-0";
40054
+
40055
+ // src/pages/leaderboard/components/leaderboard-header-row.tsx
40056
+ var import_jsx_runtime205 = require("react/jsx-runtime");
40057
+ var SORT_CARET = /* @__PURE__ */ (0, import_jsx_runtime205.jsx)("svg", { viewBox: "0 0 10 10", className: "size-2.5", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime205.jsx)("path", { d: "M5 8 1 3h8z", fill: "currentColor" }) });
40058
+ function LeaderboardHeaderRow({
40059
+ metric,
40060
+ onMetricChange
40061
+ }) {
40062
+ const labels = (0, import_hooks99.useLabels)().leaderboard;
40063
+ const sortable = (key, text) => {
40064
+ const active = metric === key;
40065
+ return /* @__PURE__ */ (0, import_jsx_runtime205.jsx)(
40066
+ "span",
40067
+ {
40068
+ role: "columnheader",
40069
+ "aria-sort": active ? "descending" : void 0,
40070
+ className: "text-right",
40071
+ children: /* @__PURE__ */ (0, import_jsx_runtime205.jsxs)(
40072
+ "button",
40073
+ {
40074
+ type: "button",
40075
+ onClick: () => onMetricChange(key),
40076
+ className: cn(
40077
+ "inline-flex cursor-pointer items-center justify-end gap-1 uppercase tracking-wide outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-agg-primary-hover",
40078
+ active ? "font-agg-bold text-agg-foreground" : "hover:text-agg-foreground"
40079
+ ),
40080
+ children: [
40081
+ text,
40082
+ active ? SORT_CARET : null
40083
+ ]
40084
+ }
40085
+ )
40086
+ }
40087
+ );
40088
+ };
40089
+ return /* @__PURE__ */ (0, import_jsx_runtime205.jsxs)(
40090
+ "div",
40091
+ {
40092
+ role: "row",
40093
+ className: cn(
40094
+ LEADERBOARD_GRID_CLASS,
40095
+ "agg-leaderboard-header hidden h-10 items-center border-b border-agg-separator bg-agg-secondary-hover px-5 text-agg-xs leading-agg-4 uppercase tracking-wide text-agg-muted-foreground sm:grid"
40096
+ ),
40097
+ children: [
40098
+ /* @__PURE__ */ (0, import_jsx_runtime205.jsx)("span", { role: "columnheader", children: labels.columns.rank }),
40099
+ /* @__PURE__ */ (0, import_jsx_runtime205.jsx)("span", { role: "columnheader", children: labels.columns.trader }),
40100
+ /* @__PURE__ */ (0, import_jsx_runtime205.jsx)("span", { role: "columnheader", className: "text-right", children: labels.columns.orders }),
40101
+ sortable("volume", labels.columns.volume),
40102
+ sortable("realizedPnl", labels.columns.realizedPnl)
40103
+ ]
40104
+ }
40105
+ );
40106
+ }
40107
+
40108
+ // src/pages/leaderboard/components/leaderboard-row.tsx
40109
+ var import_hooks100 = require("@agg-build/hooks");
40110
+ init_remote_image();
40111
+ init_utils();
40112
+ var import_jsx_runtime206 = require("react/jsx-runtime");
40113
+ var integer = new Intl.NumberFormat("en-US");
40114
+ function LeaderboardRowView({
40115
+ row,
40116
+ isCurrentUser,
40117
+ className
40118
+ }) {
40119
+ var _a, _b, _c;
40120
+ const labels = (0, import_hooks100.useLabels)().leaderboard;
40121
+ const { formatCurrency: formatCurrency2 } = (0, import_hooks100.useAggUiConfig)().formatting;
40122
+ const tone = getPositionTone(row.realizedPnl);
40123
+ const shortWallet = shortenAddress(row.walletAddress);
40124
+ const identity = (_b = (_a = row.username) != null ? _a : shortWallet) != null ? _b : labels.anonymousTrader;
40125
+ const identityKind = row.username ? "username" : shortWallet ? "wallet" : "anonymous";
40126
+ const isTop = row.rank != null && row.rank <= LEADERBOARD_TOP_RANKS;
40127
+ const hasOrders = Number.isFinite(row.orders);
40128
+ const cell = (caption2, value, extra) => /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)("span", { role: "cell", className: "flex flex-col text-left tabular-nums sm:block sm:text-right", children: [
40129
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsx)("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground sm:hidden", children: caption2 }),
40130
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsx)("span", { className: cn("text-agg-sm leading-agg-5", extra), children: value })
40131
+ ] });
40132
+ return /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)(
40133
+ "div",
40134
+ {
40135
+ role: "row",
40136
+ "aria-current": isCurrentUser ? "true" : void 0,
40137
+ className: cn(
40138
+ LEADERBOARD_GRID_CLASS,
40139
+ "agg-leaderboard-row items-center px-4 py-3 sm:min-h-16 sm:px-5",
40140
+ isCurrentUser ? "bg-agg-trade-highlight-surface shadow-[inset_3px_0_0_var(--agg-color-primary)]" : "hover:bg-agg-secondary-hover/60",
40141
+ className
40142
+ ),
40143
+ children: [
40144
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsx)(
40145
+ "span",
40146
+ {
40147
+ role: "cell",
40148
+ "data-testid": "agg-leaderboard-rank",
40149
+ className: cn(
40150
+ "agg-leaderboard-rank row-span-2 inline-flex size-7 items-center justify-center rounded-agg-full text-agg-sm tabular-nums sm:row-span-1",
40151
+ // cn() is a plain join: colour classes must be mutually exclusive.
40152
+ row.rank === 1 ? "border border-agg-primary bg-agg-secondary-hover font-agg-bold text-agg-primary" : isTop ? "border border-agg-separator bg-agg-secondary-hover font-agg-bold text-agg-foreground" : "text-agg-muted-foreground"
40153
+ ),
40154
+ children: (_c = row.rank) != null ? _c : "\u2013"
40155
+ }
40156
+ ),
40157
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)("div", { role: "cell", className: "agg-leaderboard-identity flex min-w-0 items-center gap-3", children: [
40158
+ row.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime206.jsx)(
40159
+ RemoteImage,
40160
+ {
40161
+ src: (0, import_hooks100.optimizedImageUrl)(row.avatarUrl, 80),
40162
+ alt: "",
40163
+ className: "size-10 shrink-0 rounded-agg-full object-cover"
40164
+ }
40165
+ ) : /* @__PURE__ */ (0, import_jsx_runtime206.jsx)(DefaultAvatar, { className: "size-10 rounded-agg-full" }),
40166
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)("div", { className: "flex min-w-0 flex-col", children: [
40167
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)("span", { className: "flex items-center gap-2", children: [
40168
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsx)(
40169
+ "span",
40170
+ {
40171
+ className: cn(
40172
+ "truncate text-agg-sm leading-agg-5",
40173
+ identityKind === "username" && "font-agg-bold text-agg-foreground",
40174
+ identityKind === "wallet" && "font-mono font-agg-medium text-agg-foreground",
40175
+ identityKind === "anonymous" && "font-agg-medium text-agg-muted-foreground"
40176
+ ),
40177
+ children: identity
40178
+ }
40179
+ ),
40180
+ isCurrentUser ? /* @__PURE__ */ (0, import_jsx_runtime206.jsx)("span", { className: "rounded-agg-full bg-agg-primary px-1.5 text-agg-2xs font-agg-bold uppercase leading-agg-4 tracking-wide text-agg-on-primary", children: labels.you }) : null
40181
+ ] }),
40182
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsx)("span", { className: "text-agg-xs leading-agg-4 text-agg-muted-foreground", children: hasOrders ? labels.tradesCount(row.orders) : MISSING_VALUE_LABEL })
40183
+ ] })
40184
+ ] }),
40185
+ /* @__PURE__ */ (0, import_jsx_runtime206.jsxs)("div", { className: "col-start-2 grid grid-cols-3 gap-2 sm:contents", children: [
40186
+ cell(labels.columns.orders, hasOrders ? integer.format(row.orders) : MISSING_VALUE_LABEL),
40187
+ cell(labels.columns.volume, formatCurrencyMarkingNegligible(row.volume, formatCurrency2)),
40188
+ cell(
40189
+ labels.columns.realizedPnl,
40190
+ formatSignedCurrency(row.realizedPnl, formatCurrency2, { markNegligible: true }),
40191
+ cn("font-agg-bold", toneClassName(tone))
40192
+ )
40193
+ ] })
40194
+ ]
40195
+ }
40196
+ );
40197
+ }
40198
+
40199
+ // src/pages/leaderboard/components/leaderboard-skeleton.tsx
40200
+ var import_hooks101 = require("@agg-build/hooks");
40201
+ init_utils();
40202
+ var import_jsx_runtime207 = require("react/jsx-runtime");
40203
+ function LeaderboardSkeleton({ rows = 4 }) {
40204
+ const labels = (0, import_hooks101.useLabels)().leaderboard;
40205
+ return /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("div", { role: "status", "aria-label": labels.loadingAria, className: "agg-leaderboard-skeleton", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime207.jsxs)(
40206
+ "div",
40207
+ {
40208
+ className: cn(
40209
+ LEADERBOARD_GRID_CLASS,
40210
+ "items-center border-b border-agg-separator px-4 py-3 last:border-b-0 sm:min-h-16 sm:px-5"
40211
+ ),
40212
+ children: [
40213
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "size-7 rounded-agg-full bg-agg-secondary-hover/80" }),
40214
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsxs)("div", { className: "flex items-center gap-3", children: [
40215
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "size-10 rounded-agg-full bg-agg-secondary-hover/80" }),
40216
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsxs)("div", { className: "flex flex-1 flex-col gap-2", children: [
40217
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "h-3 w-2/5 rounded-agg-sm bg-agg-secondary-hover/80" }),
40218
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "h-3 w-1/5 rounded-agg-sm bg-agg-secondary-hover/80" })
40219
+ ] })
40220
+ ] }),
40221
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "hidden h-3 w-10 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" }),
40222
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "hidden h-3 w-16 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" }),
40223
+ /* @__PURE__ */ (0, import_jsx_runtime207.jsx)("span", { className: "hidden h-3 w-14 justify-self-end rounded-agg-sm bg-agg-secondary-hover/80 sm:block" })
40224
+ ]
40225
+ },
40226
+ i
40227
+ )) });
40228
+ }
40229
+
40230
+ // src/pages/leaderboard/components/segmented-control.tsx
40231
+ init_utils();
40232
+ var import_jsx_runtime208 = require("react/jsx-runtime");
40233
+ function SegmentedControl({
40234
+ label: label2,
40235
+ value,
40236
+ onChange,
40237
+ items,
40238
+ className,
40239
+ itemClassName
40240
+ }) {
40241
+ return /* @__PURE__ */ (0, import_jsx_runtime208.jsx)(
40242
+ "div",
40243
+ {
40244
+ role: "group",
40245
+ "aria-label": label2,
40246
+ className: cn(
40247
+ "agg-segmented flex h-10 w-full items-stretch overflow-clip rounded-agg-sm border border-agg-separator sm:w-auto",
40248
+ className
40249
+ ),
40250
+ children: items.map((item, idx) => {
40251
+ const isActive = item.value === value;
40252
+ return /* @__PURE__ */ (0, import_jsx_runtime208.jsxs)("div", { className: "flex flex-1 items-stretch sm:flex-none", children: [
40253
+ idx > 0 ? /* @__PURE__ */ (0, import_jsx_runtime208.jsx)("div", { className: "w-px bg-agg-separator", "aria-hidden": true }) : null,
40254
+ /* @__PURE__ */ (0, import_jsx_runtime208.jsx)(
40255
+ "button",
40256
+ {
40257
+ type: "button",
40258
+ "aria-pressed": isActive,
40259
+ onClick: () => onChange(item.value),
40260
+ className: cn(
40261
+ "agg-segmented-trigger flex flex-1 cursor-pointer items-center justify-center px-3 font-agg-sans text-agg-sm leading-agg-5 whitespace-nowrap outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-agg-primary-hover sm:px-4",
40262
+ isActive ? "bg-agg-secondary-hover font-agg-bold text-agg-foreground" : "bg-agg-secondary font-agg-normal text-agg-muted-foreground hover:bg-agg-secondary-hover hover:text-agg-foreground",
40263
+ itemClassName
40264
+ ),
40265
+ children: item.label
40266
+ }
40267
+ )
40268
+ ] }, item.value);
40269
+ })
40270
+ }
40271
+ );
40272
+ }
40273
+
40274
+ // src/pages/leaderboard/index.tsx
40275
+ var import_jsx_runtime209 = require("react/jsx-runtime");
40276
+ function LeaderboardPage(props) {
40277
+ return /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(AggErrorBoundary, { onError: props.onError, children: /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(LeaderboardPageInner, __spreadValues({}, props)) });
40278
+ }
40279
+ function LeaderboardPageInner({
40280
+ rows: rowsProp,
40281
+ isLoading: isLoadingProp,
40282
+ error: errorProp,
40283
+ hasNextPage: hasNextPageProp,
40284
+ isLoadingMore: isLoadingMoreProp,
40285
+ onLoadMore: onLoadMoreProp,
40286
+ period: periodProp,
40287
+ onPeriodChange,
40288
+ metric: metricProp,
40289
+ onMetricChange,
40290
+ currentUserId: currentUserIdProp,
40291
+ appName,
40292
+ className,
40293
+ classNames
40294
+ }) {
40295
+ const allLabels = (0, import_hooks102.useLabels)();
40296
+ const labels = allLabels.leaderboard;
40297
+ const { user } = (0, import_hooks102.useAggAuthState)();
40298
+ const [periodState, setPeriodState] = (0, import_react69.useState)(LEADERBOARD_DEFAULT_PERIOD);
40299
+ const [metricState, setMetricState] = (0, import_react69.useState)(LEADERBOARD_DEFAULT_METRIC);
40300
+ const period = periodProp != null ? periodProp : periodState;
40301
+ const metric = metricProp != null ? metricProp : metricState;
40302
+ const handlePeriodChange = (0, import_react69.useCallback)(
40303
+ (next) => {
40304
+ if (periodProp === void 0) setPeriodState(next);
40305
+ onPeriodChange == null ? void 0 : onPeriodChange(next);
40306
+ },
40307
+ [onPeriodChange, periodProp]
40308
+ );
40309
+ const handleMetricChange = (0, import_react69.useCallback)(
40310
+ (next) => {
40311
+ if (metricProp === void 0) setMetricState(next);
40312
+ onMetricChange == null ? void 0 : onMetricChange(next);
40313
+ },
40314
+ [metricProp, onMetricChange]
40315
+ );
40316
+ const shouldUseHookData = !rowsProp;
40317
+ const query = (0, import_hooks102.useLeaderboard)({ period, metric, enabled: shouldUseHookData });
40318
+ const rows = rowsProp != null ? rowsProp : query.rows;
40319
+ const isLoading = isLoadingProp != null ? isLoadingProp : shouldUseHookData && query.isLoading;
40320
+ const error = errorProp != null ? errorProp : shouldUseHookData ? query.error : null;
40321
+ const hasNextPage = hasNextPageProp != null ? hasNextPageProp : shouldUseHookData && query.hasNextPage;
40322
+ const isLoadingMore = isLoadingMoreProp != null ? isLoadingMoreProp : shouldUseHookData && query.isFetchingNextPage;
40323
+ const fetchNextPage = query.fetchNextPage;
40324
+ const onLoadMore = (0, import_react69.useMemo)(
40325
+ () => onLoadMoreProp != null ? onLoadMoreProp : shouldUseHookData ? () => void fetchNextPage() : void 0,
40326
+ [onLoadMoreProp, shouldUseHookData, fetchNextPage]
40327
+ );
40328
+ const retry = shouldUseHookData ? () => void query.refetch() : void 0;
40329
+ const currentUserId = currentUserIdProp != null ? currentUserIdProp : user == null ? void 0 : user.id;
40330
+ const [sentinel, setSentinel] = (0, import_react69.useState)(null);
40331
+ (0, import_react69.useEffect)(() => {
40332
+ const target = sentinel;
40333
+ if (!target || !hasNextPage || !onLoadMore || typeof IntersectionObserver === "undefined")
40334
+ return;
40335
+ const observer = new IntersectionObserver(
40336
+ (entries) => {
40337
+ var _a;
40338
+ if (!((_a = entries[0]) == null ? void 0 : _a.isIntersecting) || isLoading || isLoadingMore) return;
40339
+ onLoadMore();
40340
+ },
40341
+ { rootMargin: "60px 0px" }
40342
+ );
40343
+ observer.observe(target);
40344
+ return () => observer.disconnect();
40345
+ }, [sentinel, hasNextPage, isLoading, isLoadingMore, onLoadMore]);
40346
+ const hasRows = rows.length > 0;
40347
+ const showInlineError = Boolean(error) && hasRows;
40348
+ const periodItems = import_hooks102.LEADERBOARD_PERIODS.map((value) => ({ value, label: labels.periods[value] }));
40349
+ const metricItems = LEADERBOARD_METRICS.map((value) => ({ value, label: labels.metrics[value] }));
40350
+ return /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)(
40351
+ "div",
40352
+ {
40353
+ className: cn(
40354
+ "agg-leaderboard mx-auto flex w-full max-w-[960px] flex-col px-4 py-6 sm:px-6 gap-5 font-agg-sans text-agg-foreground",
40355
+ className,
40356
+ classNames == null ? void 0 : classNames.root
40357
+ ),
40358
+ children: [
40359
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)("header", { className: cn("agg-leaderboard-title flex flex-col gap-1", classNames == null ? void 0 : classNames.header), children: [
40360
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("h1", { className: "agg-type-heading m-0", children: labels.title }),
40361
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("p", { className: "m-0 text-agg-sm leading-agg-5 text-agg-muted-foreground", children: labels.subtitle(appName, labels.periods[period]) })
40362
+ ] }),
40363
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)(
40364
+ "div",
40365
+ {
40366
+ className: cn(
40367
+ "agg-leaderboard-toolbar flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between",
40368
+ classNames == null ? void 0 : classNames.toolbar
40369
+ ),
40370
+ children: [
40371
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3", children: [
40372
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground", children: labels.periodLabel }),
40373
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40374
+ SegmentedControl,
40375
+ {
40376
+ label: labels.periodLabel,
40377
+ value: period,
40378
+ onChange: handlePeriodChange,
40379
+ items: periodItems
40380
+ }
40381
+ )
40382
+ ] }),
40383
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3", children: [
40384
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("span", { className: "agg-type-caption uppercase tracking-wide text-agg-muted-foreground", children: labels.rankByLabel }),
40385
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40386
+ SegmentedControl,
40387
+ {
40388
+ label: labels.rankByLabel,
40389
+ value: metric,
40390
+ onChange: handleMetricChange,
40391
+ items: metricItems
40392
+ }
40393
+ )
40394
+ ] })
40395
+ ]
40396
+ }
40397
+ ),
40398
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)(
40399
+ "section",
40400
+ {
40401
+ "aria-label": labels.title,
40402
+ className: cn(
40403
+ "agg-leaderboard-list overflow-clip rounded-agg-xl border border-agg-separator bg-agg-secondary shadow-agg-card",
40404
+ classNames == null ? void 0 : classNames.list
40405
+ ),
40406
+ children: [
40407
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)("div", { role: "table", "aria-label": labels.title, className: "agg-leaderboard-table", children: [
40408
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(LeaderboardHeaderRow, { metric, onMetricChange: handleMetricChange }),
40409
+ !isLoading && hasRows ? /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("div", { className: "divide-y divide-agg-separator", children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40410
+ LeaderboardRowView,
40411
+ {
40412
+ row,
40413
+ isCurrentUser: currentUserId !== void 0 && row.userId === currentUserId,
40414
+ className: classNames == null ? void 0 : classNames.row
40415
+ },
40416
+ row.userId
40417
+ )) }) : null
40418
+ ] }),
40419
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(LeaderboardSkeleton, {}) : error && !hasRows ? /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("div", { className: "py-10", children: /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40420
+ StateMessage,
40421
+ {
40422
+ title: labels.errorTitle,
40423
+ description: labels.errorDescription,
40424
+ icon: /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(Icon, { name: "warning" }),
40425
+ onAction: retry
40426
+ }
40427
+ ) }) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("div", { className: "py-10", children: /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40428
+ StateMessage,
40429
+ {
40430
+ title: labels.emptyTitle,
40431
+ description: labels.emptyDescription,
40432
+ icon: /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(Icon, { name: "search-empty" })
40433
+ }
40434
+ ) }) : null,
40435
+ (hasNextPage || showInlineError) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40436
+ "div",
40437
+ {
40438
+ className: cn(
40439
+ "agg-leaderboard-footer relative flex items-center justify-center gap-3 border-t border-agg-separator p-3.5",
40440
+ classNames == null ? void 0 : classNames.footer
40441
+ ),
40442
+ children: showInlineError ? /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)(import_jsx_runtime209.Fragment, { children: [
40443
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("span", { role: "alert", className: "text-agg-sm leading-agg-5 text-agg-error", children: labels.errorTitle }),
40444
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(Button, { variant: "tertiary", size: "small", onClick: retry != null ? retry : onLoadMore, children: allLabels.common.retry })
40445
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime209.jsxs)(import_jsx_runtime209.Fragment, { children: [
40446
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40447
+ "div",
40448
+ {
40449
+ ref: setSentinel,
40450
+ className: "agg-leaderboard-sentinel absolute inset-x-0 top-0 h-px",
40451
+ "aria-hidden": true
40452
+ }
40453
+ ),
40454
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)(
40455
+ Button,
40456
+ {
40457
+ variant: "tertiary",
40458
+ size: "small",
40459
+ onClick: onLoadMore,
40460
+ disabled: isLoadingMore,
40461
+ isLoading: isLoadingMore,
40462
+ "aria-label": labels.showMore,
40463
+ children: labels.showMore
40464
+ }
40465
+ )
40466
+ ] })
40467
+ }
40468
+ ) : null
40469
+ ]
40470
+ }
40471
+ ),
40472
+ /* @__PURE__ */ (0, import_jsx_runtime209.jsx)("p", { className: "m-0 text-agg-xs leading-agg-4 text-agg-muted-foreground", children: labels.pnlFootnote })
40473
+ ]
40474
+ }
40475
+ );
40476
+ }
40477
+ LeaderboardPage.displayName = "LeaderboardPage";
40478
+
40016
40479
  // src/pages/index.ts
40017
40480
  init_deposit_modal_events();
40018
40481
  // Annotate the CommonJS export names for ESM import in node:
@@ -40022,6 +40485,10 @@ init_deposit_modal_events();
40022
40485
  EventOpenOrders,
40023
40486
  EventOpenOrdersCard,
40024
40487
  HomePage,
40488
+ LEADERBOARD_DEFAULT_METRIC,
40489
+ LEADERBOARD_DEFAULT_PERIOD,
40490
+ LEADERBOARD_METRICS,
40491
+ LeaderboardPage,
40025
40492
  ManageBalancesModal,
40026
40493
  USER_PROFILE_TAB_ACTIVITY,
40027
40494
  USER_PROFILE_TAB_OPEN_ORDERS,