@medialane/ui 0.105.0 → 0.107.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 (141) hide show
  1. package/dist/components/asset-lightbox.cjs +66 -0
  2. package/dist/components/asset-lightbox.cjs.map +1 -0
  3. package/dist/components/asset-lightbox.d.cts +11 -0
  4. package/dist/components/asset-lightbox.d.ts +11 -0
  5. package/dist/components/asset-lightbox.js +42 -0
  6. package/dist/components/asset-lightbox.js.map +1 -0
  7. package/dist/components/club-owner-actions.cjs +56 -0
  8. package/dist/components/club-owner-actions.cjs.map +1 -0
  9. package/dist/components/club-owner-actions.d.cts +11 -0
  10. package/dist/components/club-owner-actions.d.ts +11 -0
  11. package/dist/components/club-owner-actions.js +22 -0
  12. package/dist/components/club-owner-actions.js.map +1 -0
  13. package/dist/components/collection-activity-tab.cjs +60 -0
  14. package/dist/components/collection-activity-tab.cjs.map +1 -0
  15. package/dist/components/collection-activity-tab.d.cts +10 -0
  16. package/dist/components/collection-activity-tab.d.ts +10 -0
  17. package/dist/components/collection-activity-tab.js +36 -0
  18. package/dist/components/collection-activity-tab.js.map +1 -0
  19. package/dist/components/collection-traits-tab.cjs +79 -0
  20. package/dist/components/collection-traits-tab.cjs.map +1 -0
  21. package/dist/components/collection-traits-tab.d.cts +10 -0
  22. package/dist/components/collection-traits-tab.d.ts +10 -0
  23. package/dist/components/collection-traits-tab.js +55 -0
  24. package/dist/components/collection-traits-tab.js.map +1 -0
  25. package/dist/components/create-form-primitives.cjs +61 -0
  26. package/dist/components/create-form-primitives.cjs.map +1 -0
  27. package/dist/components/create-form-primitives.d.cts +16 -0
  28. package/dist/components/create-form-primitives.d.ts +16 -0
  29. package/dist/components/create-form-primitives.js +36 -0
  30. package/dist/components/create-form-primitives.js.map +1 -0
  31. package/dist/components/creation-record.cjs +86 -0
  32. package/dist/components/creation-record.cjs.map +1 -0
  33. package/dist/components/creation-record.d.cts +14 -0
  34. package/dist/components/creation-record.d.ts +14 -0
  35. package/dist/components/creation-record.js +52 -0
  36. package/dist/components/creation-record.js.map +1 -0
  37. package/dist/components/creator-chip.cjs +58 -0
  38. package/dist/components/creator-chip.cjs.map +1 -0
  39. package/dist/components/creator-chip.d.cts +10 -0
  40. package/dist/components/creator-chip.d.ts +10 -0
  41. package/dist/components/creator-chip.js +24 -0
  42. package/dist/components/creator-chip.js.map +1 -0
  43. package/dist/components/creator-score-inline.cjs +52 -0
  44. package/dist/components/creator-score-inline.cjs.map +1 -0
  45. package/dist/components/creator-score-inline.d.cts +19 -0
  46. package/dist/components/creator-score-inline.d.ts +19 -0
  47. package/dist/components/creator-score-inline.js +18 -0
  48. package/dist/components/creator-score-inline.js.map +1 -0
  49. package/dist/components/dialog.d.cts +9 -9
  50. package/dist/components/dialog.d.ts +9 -9
  51. package/dist/components/ip-type-fields.cjs +307 -0
  52. package/dist/components/ip-type-fields.cjs.map +1 -0
  53. package/dist/components/ip-type-fields.d.cts +17 -0
  54. package/dist/components/ip-type-fields.d.ts +17 -0
  55. package/dist/components/ip-type-fields.js +293 -0
  56. package/dist/components/ip-type-fields.js.map +1 -0
  57. package/dist/components/json-ld.cjs +39 -0
  58. package/dist/components/json-ld.cjs.map +1 -0
  59. package/dist/components/json-ld.d.cts +8 -0
  60. package/dist/components/json-ld.d.ts +8 -0
  61. package/dist/components/json-ld.js +15 -0
  62. package/dist/components/json-ld.js.map +1 -0
  63. package/dist/components/nav-theme-toggle.cjs +66 -0
  64. package/dist/components/nav-theme-toggle.cjs.map +1 -0
  65. package/dist/components/nav-theme-toggle.d.cts +9 -0
  66. package/dist/components/nav-theme-toggle.d.ts +9 -0
  67. package/dist/components/nav-theme-toggle.js +42 -0
  68. package/dist/components/nav-theme-toggle.js.map +1 -0
  69. package/dist/components/order-sort-control.cjs +58 -0
  70. package/dist/components/order-sort-control.cjs.map +1 -0
  71. package/dist/components/order-sort-control.d.cts +13 -0
  72. package/dist/components/order-sort-control.d.ts +13 -0
  73. package/dist/components/order-sort-control.js +39 -0
  74. package/dist/components/order-sort-control.js.map +1 -0
  75. package/dist/components/portfolio-activity.cjs +117 -0
  76. package/dist/components/portfolio-activity.cjs.map +1 -0
  77. package/dist/components/portfolio-activity.d.cts +10 -0
  78. package/dist/components/portfolio-activity.d.ts +10 -0
  79. package/dist/components/portfolio-activity.js +93 -0
  80. package/dist/components/portfolio-activity.js.map +1 -0
  81. package/dist/components/price-history-chart.cjs +130 -0
  82. package/dist/components/price-history-chart.cjs.map +1 -0
  83. package/dist/components/price-history-chart.d.cts +9 -0
  84. package/dist/components/price-history-chart.d.ts +9 -0
  85. package/dist/components/price-history-chart.js +114 -0
  86. package/dist/components/price-history-chart.js.map +1 -0
  87. package/dist/components/sheet.cjs +160 -0
  88. package/dist/components/sheet.cjs.map +1 -0
  89. package/dist/components/sheet.d.cts +30 -0
  90. package/dist/components/sheet.d.ts +30 -0
  91. package/dist/components/sheet.js +117 -0
  92. package/dist/components/sheet.js.map +1 -0
  93. package/dist/components/textarea.cjs +57 -0
  94. package/dist/components/textarea.cjs.map +1 -0
  95. package/dist/components/textarea.d.cts +6 -0
  96. package/dist/components/textarea.d.ts +6 -0
  97. package/dist/components/textarea.js +23 -0
  98. package/dist/components/textarea.js.map +1 -0
  99. package/dist/index.cjs +110 -0
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.d.cts +24 -2
  102. package/dist/index.d.ts +24 -2
  103. package/dist/index.js +88 -0
  104. package/dist/index.js.map +1 -1
  105. package/dist/utils/format-activity.cjs +143 -0
  106. package/dist/utils/format-activity.cjs.map +1 -0
  107. package/dist/utils/format-activity.d.cts +14 -0
  108. package/dist/utils/format-activity.d.ts +14 -0
  109. package/dist/utils/format-activity.js +116 -0
  110. package/dist/utils/format-activity.js.map +1 -0
  111. package/dist/utils/proxy-body.cjs +60 -0
  112. package/dist/utils/proxy-body.cjs.map +1 -0
  113. package/dist/utils/proxy-body.d.cts +22 -0
  114. package/dist/utils/proxy-body.d.ts +22 -0
  115. package/dist/utils/proxy-body.js +36 -0
  116. package/dist/utils/proxy-body.js.map +1 -0
  117. package/dist/utils/query-keys.cjs +80 -0
  118. package/dist/utils/query-keys.cjs.map +1 -0
  119. package/dist/utils/query-keys.d.cts +39 -0
  120. package/dist/utils/query-keys.d.ts +39 -0
  121. package/dist/utils/query-keys.js +54 -0
  122. package/dist/utils/query-keys.js.map +1 -0
  123. package/dist/utils/use-activities.cjs +68 -0
  124. package/dist/utils/use-activities.cjs.map +1 -0
  125. package/dist/utils/use-activities.d.cts +20 -0
  126. package/dist/utils/use-activities.d.ts +20 -0
  127. package/dist/utils/use-activities.js +33 -0
  128. package/dist/utils/use-activities.js.map +1 -0
  129. package/dist/utils/use-collections.cjs +113 -0
  130. package/dist/utils/use-collections.cjs.map +1 -0
  131. package/dist/utils/use-collections.d.cts +43 -0
  132. package/dist/utils/use-collections.d.ts +43 -0
  133. package/dist/utils/use-collections.js +75 -0
  134. package/dist/utils/use-collections.js.map +1 -0
  135. package/dist/utils/use-profiles.cjs +69 -0
  136. package/dist/utils/use-profiles.cjs.map +1 -0
  137. package/dist/utils/use-profiles.d.cts +18 -0
  138. package/dist/utils/use-profiles.d.ts +18 -0
  139. package/dist/utils/use-profiles.js +34 -0
  140. package/dist/utils/use-profiles.js.map +1 -0
  141. package/package.json +2 -2
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiOrder } from '@medialane/sdk';
3
+
4
+ type OrderSort = "recent" | "price_asc" | "price_desc";
5
+ /** Pure — orders already come from the API sorted "recent"; this only
6
+ * re-sorts the in-memory page by price.raw (BigInt-safe wei comparison). */
7
+ declare function sortOrders(orders: ApiOrder[], sort: OrderSort): ApiOrder[];
8
+ declare function OrderSortControl({ value, onChange }: {
9
+ value: OrderSort;
10
+ onChange: (v: OrderSort) => void;
11
+ }): react_jsx_runtime.JSX.Element;
12
+
13
+ export { type OrderSort, OrderSortControl, sortOrders };
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiOrder } from '@medialane/sdk';
3
+
4
+ type OrderSort = "recent" | "price_asc" | "price_desc";
5
+ /** Pure — orders already come from the API sorted "recent"; this only
6
+ * re-sorts the in-memory page by price.raw (BigInt-safe wei comparison). */
7
+ declare function sortOrders(orders: ApiOrder[], sort: OrderSort): ApiOrder[];
8
+ declare function OrderSortControl({ value, onChange }: {
9
+ value: OrderSort;
10
+ onChange: (v: OrderSort) => void;
11
+ }): react_jsx_runtime.JSX.Element;
12
+
13
+ export { type OrderSort, OrderSortControl, sortOrders };
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { ArrowDownUp } from "lucide-react";
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue
10
+ } from "./select.js";
11
+ const LABELS = {
12
+ recent: "Recently listed",
13
+ price_asc: "Price: low to high",
14
+ price_desc: "Price: high to low"
15
+ };
16
+ function sortOrders(orders, sort) {
17
+ if (sort === "recent") return orders;
18
+ const withPrice = orders.filter((o) => o.price.raw != null);
19
+ const withoutPrice = orders.filter((o) => o.price.raw == null);
20
+ const sorted = [...withPrice].sort((a, b) => {
21
+ const diff = BigInt(a.price.raw) - BigInt(b.price.raw);
22
+ return sort === "price_asc" ? diff < 0n ? -1 : diff > 0n ? 1 : 0 : diff > 0n ? -1 : diff < 0n ? 1 : 0;
23
+ });
24
+ return [...sorted, ...withoutPrice];
25
+ }
26
+ function OrderSortControl({ value, onChange }) {
27
+ return /* @__PURE__ */ jsxs(Select, { value, onValueChange: (v) => onChange(v), children: [
28
+ /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-[180px] h-9 text-xs gap-1.5", children: [
29
+ /* @__PURE__ */ jsx(ArrowDownUp, { className: "h-3.5 w-3.5 text-muted-foreground" }),
30
+ /* @__PURE__ */ jsx(SelectValue, {})
31
+ ] }),
32
+ /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(LABELS).map((k) => /* @__PURE__ */ jsx(SelectItem, { value: k, className: "text-xs", children: LABELS[k] }, k)) })
33
+ ] });
34
+ }
35
+ export {
36
+ OrderSortControl,
37
+ sortOrders
38
+ };
39
+ //# sourceMappingURL=order-sort-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/order-sort-control.tsx"],"sourcesContent":["\"use client\";\n\nimport { ArrowDownUp } from \"lucide-react\";\nimport type { ApiOrder } from \"@medialane/sdk\";\nimport {\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue,\n} from \"./select.js\";\n\nexport type OrderSort = \"recent\" | \"price_asc\" | \"price_desc\";\n\nconst LABELS: Record<OrderSort, string> = {\n recent: \"Recently listed\",\n price_asc: \"Price: low to high\",\n price_desc: \"Price: high to low\",\n};\n\n/** Pure — orders already come from the API sorted \"recent\"; this only\n * re-sorts the in-memory page by price.raw (BigInt-safe wei comparison). */\nexport function sortOrders(orders: ApiOrder[], sort: OrderSort): ApiOrder[] {\n if (sort === \"recent\") return orders;\n const withPrice = orders.filter((o) => o.price.raw != null);\n const withoutPrice = orders.filter((o) => o.price.raw == null);\n const sorted = [...withPrice].sort((a, b) => {\n const diff = BigInt(a.price.raw!) - BigInt(b.price.raw!);\n return sort === \"price_asc\" ? (diff < 0n ? -1 : diff > 0n ? 1 : 0) : (diff > 0n ? -1 : diff < 0n ? 1 : 0);\n });\n return [...sorted, ...withoutPrice];\n}\n\nexport function OrderSortControl({ value, onChange }: { value: OrderSort; onChange: (v: OrderSort) => void }) {\n return (\n <Select value={value} onValueChange={(v) => onChange(v as OrderSort)}>\n <SelectTrigger className=\"w-[180px] h-9 text-xs gap-1.5\">\n <ArrowDownUp className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {(Object.keys(LABELS) as OrderSort[]).map((k) => (\n <SelectItem key={k} value={k} className=\"text-xs\">{LABELS[k]}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":";AAgCM,SACE,KADF;AA9BN,SAAS,mBAAmB;AAE5B;AAAA,EACE;AAAA,EAAQ;AAAA,EAAe;AAAA,EAAY;AAAA,EAAe;AAAA,OAC7C;AAIP,MAAM,SAAoC;AAAA,EACxC,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,YAAY;AACd;AAIO,SAAS,WAAW,QAAoB,MAA6B;AAC1E,MAAI,SAAS,SAAU,QAAO;AAC9B,QAAM,YAAY,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,OAAO,IAAI;AAC1D,QAAM,eAAe,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,OAAO,IAAI;AAC7D,QAAM,SAAS,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM;AAC3C,UAAM,OAAO,OAAO,EAAE,MAAM,GAAI,IAAI,OAAO,EAAE,MAAM,GAAI;AACvD,WAAO,SAAS,cAAe,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI,IAAM,OAAO,KAAK,KAAK,OAAO,KAAK,IAAI;AAAA,EACzG,CAAC;AACD,SAAO,CAAC,GAAG,QAAQ,GAAG,YAAY;AACpC;AAEO,SAAS,iBAAiB,EAAE,OAAO,SAAS,GAA2D;AAC5G,SACE,qBAAC,UAAO,OAAc,eAAe,CAAC,MAAM,SAAS,CAAc,GACjE;AAAA,yBAAC,iBAAc,WAAU,iCACvB;AAAA,0BAAC,eAAY,WAAU,qCAAoC;AAAA,MAC3D,oBAAC,eAAY;AAAA,OACf;AAAA,IACA,oBAAC,iBACG,iBAAO,KAAK,MAAM,EAAkB,IAAI,CAAC,MACzC,oBAAC,cAAmB,OAAO,GAAG,WAAU,WAAW,iBAAO,CAAC,KAA1C,CAA4C,CAC9D,GACH;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,117 @@
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 portfolio_activity_exports = {};
21
+ __export(portfolio_activity_exports, {
22
+ PortfolioActivity: () => PortfolioActivity
23
+ });
24
+ module.exports = __toCommonJS(portfolio_activity_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_react = require("react");
27
+ var import_lucide_react = require("lucide-react");
28
+ var import_sdk = require("@medialane/sdk");
29
+ var import_use_activities = require("../utils/use-activities.js");
30
+ var import_empty_or_error = require("./empty-or-error.js");
31
+ var import_activity = require("../data/activity.js");
32
+ var import_activity_row = require("./activity-row.js");
33
+ var import_cn = require("../utils/cn.js");
34
+ const EXPLORER_URL = process.env.NEXT_PUBLIC_EXPLORER_URL || "https://voyager.online";
35
+ function PortfolioActivity({ getClient, address }) {
36
+ const { activities, isLoading, error, mutate } = (0, import_use_activities.useActivitiesByAddress)(getClient, address);
37
+ const [typeFilter, setTypeFilter] = (0, import_react.useState)("");
38
+ const displayed = typeFilter ? activities.filter((a) => a.type === typeFilter) : activities;
39
+ const typeCounts = (0, import_react.useMemo)(() => {
40
+ const counts = {};
41
+ for (const a of activities) {
42
+ counts[a.type] = (counts[a.type] ?? 0) + 1;
43
+ }
44
+ return counts;
45
+ }, [activities]);
46
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-4", children: [
47
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-2", children: import_activity.TYPE_FILTERS.map((f) => {
48
+ const typeConfig = f.value ? import_activity.ACTIVITY_TYPE_CONFIG[f.value] : null;
49
+ const Icon = typeConfig?.icon;
50
+ const count = f.value ? typeCounts[f.value] : activities.length;
51
+ const isActive = typeFilter === f.value;
52
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
53
+ "button",
54
+ {
55
+ onClick: () => setTypeFilter(f.value),
56
+ className: (0, import_cn.cn)(
57
+ "flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full transition-all font-medium",
58
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "bg-muted text-muted-foreground hover:bg-muted/70 hover:text-foreground"
59
+ ),
60
+ children: [
61
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
+ Icon,
63
+ {
64
+ className: (0, import_cn.cn)(
65
+ "h-3 w-3",
66
+ isActive ? "text-primary-foreground" : typeConfig?.colorClass
67
+ )
68
+ }
69
+ ),
70
+ f.label,
71
+ !isLoading && count != null && count > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
72
+ "span",
73
+ {
74
+ className: (0, import_cn.cn)(
75
+ "text-[10px] font-bold tabular-nums",
76
+ isActive ? "text-primary-foreground/70" : "text-muted-foreground/60"
77
+ ),
78
+ children: count
79
+ }
80
+ )
81
+ ]
82
+ },
83
+ f.value
84
+ );
85
+ }) }),
86
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
87
+ import_empty_or_error.EmptyOrError,
88
+ {
89
+ isLoading,
90
+ error,
91
+ isEmpty: displayed.length === 0,
92
+ onRetry: mutate,
93
+ emptyTitle: typeFilter ? `No ${typeFilter} events yet` : "No activity yet",
94
+ emptyDescription: "Start by listing or buying an asset on the marketplace.",
95
+ emptyCta: { label: "Browse marketplace", href: "/marketplace" },
96
+ emptyIcon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Activity, { className: "h-7 w-7 text-muted-foreground" }),
97
+ skeletonCount: 8,
98
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-xl border border-border overflow-hidden divide-y divide-border/50", children: displayed.map((activity, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
99
+ import_activity_row.ActivityRow,
100
+ {
101
+ activity,
102
+ showActor: false,
103
+ showExplorer: true,
104
+ explorerUrl: EXPLORER_URL,
105
+ getAssetHref: (c, t) => (0, import_sdk.assetHref)("STARKNET", c, t)
106
+ },
107
+ `${activity.txHash}-${activity.type}-${i}`
108
+ )) })
109
+ }
110
+ )
111
+ ] });
112
+ }
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ PortfolioActivity
116
+ });
117
+ //# sourceMappingURL=portfolio-activity.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/portfolio-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport type { MedialaneClient } from \"@medialane/sdk/starknet\";\nimport { Activity } from \"lucide-react\";\nimport { assetHref } from \"@medialane/sdk\";\nimport { useActivitiesByAddress } from \"../utils/use-activities.js\";\nimport { EmptyOrError } from \"./empty-or-error.js\";\nimport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"../data/activity.js\";\nimport { ActivityRow } from \"./activity-row.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst EXPLORER_URL = process.env.NEXT_PUBLIC_EXPLORER_URL || \"https://voyager.online\";\n\nexport interface PortfolioActivityProps {\n getClient: () => MedialaneClient;\n address: string | null;\n}\n\nexport function PortfolioActivity({ getClient, address }: PortfolioActivityProps) {\n const { activities, isLoading, error, mutate } = useActivitiesByAddress(getClient, address);\n const [typeFilter, setTypeFilter] = useState(\"\");\n\n const displayed = typeFilter\n ? activities.filter((a) => a.type === typeFilter)\n : activities;\n\n // Per-type counts for the filter chip badges\n const typeCounts = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of activities) {\n counts[a.type] = (counts[a.type] ?? 0) + 1;\n }\n return counts;\n }, [activities]);\n\n return (\n <div className=\"space-y-4\">\n {/* Filter chips with icons + per-type counts */}\n <div className=\"flex flex-wrap gap-2\">\n {TYPE_FILTERS.map((f) => {\n const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;\n const Icon = typeConfig?.icon;\n const count = f.value ? typeCounts[f.value] : activities.length;\n const isActive = typeFilter === f.value;\n return (\n <button\n key={f.value}\n onClick={() => setTypeFilter(f.value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full transition-all font-medium\",\n isActive\n ? \"bg-primary text-primary-foreground shadow-sm\"\n : \"bg-muted text-muted-foreground hover:bg-muted/70 hover:text-foreground\"\n )}\n >\n {Icon && (\n <Icon\n className={cn(\n \"h-3 w-3\",\n isActive ? \"text-primary-foreground\" : typeConfig?.colorClass\n )}\n />\n )}\n {f.label}\n {!isLoading && count != null && count > 0 && (\n <span\n className={cn(\n \"text-[10px] font-bold tabular-nums\",\n isActive\n ? \"text-primary-foreground/70\"\n : \"text-muted-foreground/60\"\n )}\n >\n {count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n <EmptyOrError\n isLoading={isLoading}\n error={error}\n isEmpty={displayed.length === 0}\n onRetry={mutate}\n emptyTitle={typeFilter ? `No ${typeFilter} events yet` : \"No activity yet\"}\n emptyDescription=\"Start by listing or buying an asset on the marketplace.\"\n emptyCta={{ label: \"Browse marketplace\", href: \"/marketplace\" }}\n emptyIcon={<Activity className=\"h-7 w-7 text-muted-foreground\" />}\n skeletonCount={8}\n >\n <div className=\"rounded-xl border border-border overflow-hidden divide-y divide-border/50\">\n {displayed.map((activity, i) => (\n <ActivityRow\n key={`${activity.txHash}-${activity.type}-${i}`}\n activity={activity}\n showActor={false}\n showExplorer\n explorerUrl={EXPLORER_URL}\n getAssetHref={(c, t) => assetHref(\"STARKNET\", c, t)}\n />\n ))}\n </div>\n </EmptyOrError>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CY;AA5CZ,mBAAkC;AAElC,0BAAyB;AACzB,iBAA0B;AAC1B,4BAAuC;AACvC,4BAA6B;AAC7B,sBAAmD;AACnD,0BAA4B;AAC5B,gBAAmB;AAEnB,MAAM,eAAe,QAAQ,IAAI,4BAA4B;AAOtD,SAAS,kBAAkB,EAAE,WAAW,QAAQ,GAA2B;AAChF,QAAM,EAAE,YAAY,WAAW,OAAO,OAAO,QAAI,8CAAuB,WAAW,OAAO;AAC1F,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,EAAE;AAE/C,QAAM,YAAY,aACd,WAAW,OAAO,CAAC,MAAM,EAAE,SAAS,UAAU,IAC9C;AAGJ,QAAM,iBAAa,sBAAQ,MAAM;AAC/B,UAAM,SAAiC,CAAC;AACxC,eAAW,KAAK,YAAY;AAC1B,aAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,KAAK;AAAA,IAC3C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,CAAC;AAEf,SACE,6CAAC,SAAI,WAAU,aAEb;AAAA,gDAAC,SAAI,WAAU,wBACZ,uCAAa,IAAI,CAAC,MAAM;AACvB,YAAM,aAAa,EAAE,QAAQ,qCAAqB,EAAE,KAAK,IAAI;AAC7D,YAAM,OAAO,YAAY;AACzB,YAAM,QAAQ,EAAE,QAAQ,WAAW,EAAE,KAAK,IAAI,WAAW;AACzD,YAAM,WAAW,eAAe,EAAE;AAClC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM,cAAc,EAAE,KAAK;AAAA,UACpC,eAAW;AAAA,YACT;AAAA,YACA,WACI,iDACA;AAAA,UACN;AAAA,UAEC;AAAA,oBACC;AAAA,cAAC;AAAA;AAAA,gBACC,eAAW;AAAA,kBACT;AAAA,kBACA,WAAW,4BAA4B,YAAY;AAAA,gBACrD;AAAA;AAAA,YACF;AAAA,YAED,EAAE;AAAA,YACF,CAAC,aAAa,SAAS,QAAQ,QAAQ,KACtC;AAAA,cAAC;AAAA;AAAA,gBACC,eAAW;AAAA,kBACT;AAAA,kBACA,WACI,+BACA;AAAA,gBACN;AAAA,gBAEC;AAAA;AAAA,YACH;AAAA;AAAA;AAAA,QA5BG,EAAE;AAAA,MA8BT;AAAA,IAEJ,CAAC,GACH;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,SAAS,UAAU,WAAW;AAAA,QAC9B,SAAS;AAAA,QACT,YAAY,aAAa,MAAM,UAAU,gBAAgB;AAAA,QACzD,kBAAiB;AAAA,QACjB,UAAU,EAAE,OAAO,sBAAsB,MAAM,eAAe;AAAA,QAC9D,WAAW,4CAAC,gCAAS,WAAU,iCAAgC;AAAA,QAC/D,eAAe;AAAA,QAEf,sDAAC,SAAI,WAAU,6EACZ,oBAAU,IAAI,CAAC,UAAU,MACxB;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,WAAW;AAAA,YACX,cAAY;AAAA,YACZ,aAAa;AAAA,YACb,cAAc,CAAC,GAAG,UAAM,sBAAU,YAAY,GAAG,CAAC;AAAA;AAAA,UAL7C,GAAG,SAAS,MAAM,IAAI,SAAS,IAAI,IAAI,CAAC;AAAA,QAM/C,CACD,GACH;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { MedialaneClient } from '@medialane/sdk/starknet';
3
+
4
+ interface PortfolioActivityProps {
5
+ getClient: () => MedialaneClient;
6
+ address: string | null;
7
+ }
8
+ declare function PortfolioActivity({ getClient, address }: PortfolioActivityProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { PortfolioActivity, type PortfolioActivityProps };
@@ -0,0 +1,10 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { MedialaneClient } from '@medialane/sdk/starknet';
3
+
4
+ interface PortfolioActivityProps {
5
+ getClient: () => MedialaneClient;
6
+ address: string | null;
7
+ }
8
+ declare function PortfolioActivity({ getClient, address }: PortfolioActivityProps): react_jsx_runtime.JSX.Element;
9
+
10
+ export { PortfolioActivity, type PortfolioActivityProps };
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useMemo } from "react";
4
+ import { Activity } from "lucide-react";
5
+ import { assetHref } from "@medialane/sdk";
6
+ import { useActivitiesByAddress } from "../utils/use-activities.js";
7
+ import { EmptyOrError } from "./empty-or-error.js";
8
+ import { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from "../data/activity.js";
9
+ import { ActivityRow } from "./activity-row.js";
10
+ import { cn } from "../utils/cn.js";
11
+ const EXPLORER_URL = process.env.NEXT_PUBLIC_EXPLORER_URL || "https://voyager.online";
12
+ function PortfolioActivity({ getClient, address }) {
13
+ const { activities, isLoading, error, mutate } = useActivitiesByAddress(getClient, address);
14
+ const [typeFilter, setTypeFilter] = useState("");
15
+ const displayed = typeFilter ? activities.filter((a) => a.type === typeFilter) : activities;
16
+ const typeCounts = useMemo(() => {
17
+ const counts = {};
18
+ for (const a of activities) {
19
+ counts[a.type] = (counts[a.type] ?? 0) + 1;
20
+ }
21
+ return counts;
22
+ }, [activities]);
23
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
24
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: TYPE_FILTERS.map((f) => {
25
+ const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;
26
+ const Icon = typeConfig?.icon;
27
+ const count = f.value ? typeCounts[f.value] : activities.length;
28
+ const isActive = typeFilter === f.value;
29
+ return /* @__PURE__ */ jsxs(
30
+ "button",
31
+ {
32
+ onClick: () => setTypeFilter(f.value),
33
+ className: cn(
34
+ "flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full transition-all font-medium",
35
+ isActive ? "bg-primary text-primary-foreground shadow-sm" : "bg-muted text-muted-foreground hover:bg-muted/70 hover:text-foreground"
36
+ ),
37
+ children: [
38
+ Icon && /* @__PURE__ */ jsx(
39
+ Icon,
40
+ {
41
+ className: cn(
42
+ "h-3 w-3",
43
+ isActive ? "text-primary-foreground" : typeConfig?.colorClass
44
+ )
45
+ }
46
+ ),
47
+ f.label,
48
+ !isLoading && count != null && count > 0 && /* @__PURE__ */ jsx(
49
+ "span",
50
+ {
51
+ className: cn(
52
+ "text-[10px] font-bold tabular-nums",
53
+ isActive ? "text-primary-foreground/70" : "text-muted-foreground/60"
54
+ ),
55
+ children: count
56
+ }
57
+ )
58
+ ]
59
+ },
60
+ f.value
61
+ );
62
+ }) }),
63
+ /* @__PURE__ */ jsx(
64
+ EmptyOrError,
65
+ {
66
+ isLoading,
67
+ error,
68
+ isEmpty: displayed.length === 0,
69
+ onRetry: mutate,
70
+ emptyTitle: typeFilter ? `No ${typeFilter} events yet` : "No activity yet",
71
+ emptyDescription: "Start by listing or buying an asset on the marketplace.",
72
+ emptyCta: { label: "Browse marketplace", href: "/marketplace" },
73
+ emptyIcon: /* @__PURE__ */ jsx(Activity, { className: "h-7 w-7 text-muted-foreground" }),
74
+ skeletonCount: 8,
75
+ children: /* @__PURE__ */ jsx("div", { className: "rounded-xl border border-border overflow-hidden divide-y divide-border/50", children: displayed.map((activity, i) => /* @__PURE__ */ jsx(
76
+ ActivityRow,
77
+ {
78
+ activity,
79
+ showActor: false,
80
+ showExplorer: true,
81
+ explorerUrl: EXPLORER_URL,
82
+ getAssetHref: (c, t) => assetHref("STARKNET", c, t)
83
+ },
84
+ `${activity.txHash}-${activity.type}-${i}`
85
+ )) })
86
+ }
87
+ )
88
+ ] });
89
+ }
90
+ export {
91
+ PortfolioActivity
92
+ };
93
+ //# sourceMappingURL=portfolio-activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/portfolio-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport type { MedialaneClient } from \"@medialane/sdk/starknet\";\nimport { Activity } from \"lucide-react\";\nimport { assetHref } from \"@medialane/sdk\";\nimport { useActivitiesByAddress } from \"../utils/use-activities.js\";\nimport { EmptyOrError } from \"./empty-or-error.js\";\nimport { ACTIVITY_TYPE_CONFIG, TYPE_FILTERS } from \"../data/activity.js\";\nimport { ActivityRow } from \"./activity-row.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst EXPLORER_URL = process.env.NEXT_PUBLIC_EXPLORER_URL || \"https://voyager.online\";\n\nexport interface PortfolioActivityProps {\n getClient: () => MedialaneClient;\n address: string | null;\n}\n\nexport function PortfolioActivity({ getClient, address }: PortfolioActivityProps) {\n const { activities, isLoading, error, mutate } = useActivitiesByAddress(getClient, address);\n const [typeFilter, setTypeFilter] = useState(\"\");\n\n const displayed = typeFilter\n ? activities.filter((a) => a.type === typeFilter)\n : activities;\n\n // Per-type counts for the filter chip badges\n const typeCounts = useMemo(() => {\n const counts: Record<string, number> = {};\n for (const a of activities) {\n counts[a.type] = (counts[a.type] ?? 0) + 1;\n }\n return counts;\n }, [activities]);\n\n return (\n <div className=\"space-y-4\">\n {/* Filter chips with icons + per-type counts */}\n <div className=\"flex flex-wrap gap-2\">\n {TYPE_FILTERS.map((f) => {\n const typeConfig = f.value ? ACTIVITY_TYPE_CONFIG[f.value] : null;\n const Icon = typeConfig?.icon;\n const count = f.value ? typeCounts[f.value] : activities.length;\n const isActive = typeFilter === f.value;\n return (\n <button\n key={f.value}\n onClick={() => setTypeFilter(f.value)}\n className={cn(\n \"flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full transition-all font-medium\",\n isActive\n ? \"bg-primary text-primary-foreground shadow-sm\"\n : \"bg-muted text-muted-foreground hover:bg-muted/70 hover:text-foreground\"\n )}\n >\n {Icon && (\n <Icon\n className={cn(\n \"h-3 w-3\",\n isActive ? \"text-primary-foreground\" : typeConfig?.colorClass\n )}\n />\n )}\n {f.label}\n {!isLoading && count != null && count > 0 && (\n <span\n className={cn(\n \"text-[10px] font-bold tabular-nums\",\n isActive\n ? \"text-primary-foreground/70\"\n : \"text-muted-foreground/60\"\n )}\n >\n {count}\n </span>\n )}\n </button>\n );\n })}\n </div>\n\n <EmptyOrError\n isLoading={isLoading}\n error={error}\n isEmpty={displayed.length === 0}\n onRetry={mutate}\n emptyTitle={typeFilter ? `No ${typeFilter} events yet` : \"No activity yet\"}\n emptyDescription=\"Start by listing or buying an asset on the marketplace.\"\n emptyCta={{ label: \"Browse marketplace\", href: \"/marketplace\" }}\n emptyIcon={<Activity className=\"h-7 w-7 text-muted-foreground\" />}\n skeletonCount={8}\n >\n <div className=\"rounded-xl border border-border overflow-hidden divide-y divide-border/50\">\n {displayed.map((activity, i) => (\n <ActivityRow\n key={`${activity.txHash}-${activity.type}-${i}`}\n activity={activity}\n showActor={false}\n showExplorer\n explorerUrl={EXPLORER_URL}\n getAssetHref={(c, t) => assetHref(\"STARKNET\", c, t)}\n />\n ))}\n </div>\n </EmptyOrError>\n </div>\n );\n}\n"],"mappings":";AA8CY,SAWI,KAXJ;AA5CZ,SAAS,UAAU,eAAe;AAElC,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB,oBAAoB;AACnD,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AAEnB,MAAM,eAAe,QAAQ,IAAI,4BAA4B;AAOtD,SAAS,kBAAkB,EAAE,WAAW,QAAQ,GAA2B;AAChF,QAAM,EAAE,YAAY,WAAW,OAAO,OAAO,IAAI,uBAAuB,WAAW,OAAO;AAC1F,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,EAAE;AAE/C,QAAM,YAAY,aACd,WAAW,OAAO,CAAC,MAAM,EAAE,SAAS,UAAU,IAC9C;AAGJ,QAAM,aAAa,QAAQ,MAAM;AAC/B,UAAM,SAAiC,CAAC;AACxC,eAAW,KAAK,YAAY;AAC1B,aAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,KAAK;AAAA,IAC3C;AACA,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,CAAC;AAEf,SACE,qBAAC,SAAI,WAAU,aAEb;AAAA,wBAAC,SAAI,WAAU,wBACZ,uBAAa,IAAI,CAAC,MAAM;AACvB,YAAM,aAAa,EAAE,QAAQ,qBAAqB,EAAE,KAAK,IAAI;AAC7D,YAAM,OAAO,YAAY;AACzB,YAAM,QAAQ,EAAE,QAAQ,WAAW,EAAE,KAAK,IAAI,WAAW;AACzD,YAAM,WAAW,eAAe,EAAE;AAClC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM,cAAc,EAAE,KAAK;AAAA,UACpC,WAAW;AAAA,YACT;AAAA,YACA,WACI,iDACA;AAAA,UACN;AAAA,UAEC;AAAA,oBACC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,WAAW,4BAA4B,YAAY;AAAA,gBACrD;AAAA;AAAA,YACF;AAAA,YAED,EAAE;AAAA,YACF,CAAC,aAAa,SAAS,QAAQ,QAAQ,KACtC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,WACI,+BACA;AAAA,gBACN;AAAA,gBAEC;AAAA;AAAA,YACH;AAAA;AAAA;AAAA,QA5BG,EAAE;AAAA,MA8BT;AAAA,IAEJ,CAAC,GACH;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,SAAS,UAAU,WAAW;AAAA,QAC9B,SAAS;AAAA,QACT,YAAY,aAAa,MAAM,UAAU,gBAAgB;AAAA,QACzD,kBAAiB;AAAA,QACjB,UAAU,EAAE,OAAO,sBAAsB,MAAM,eAAe;AAAA,QAC9D,WAAW,oBAAC,YAAS,WAAU,iCAAgC;AAAA,QAC/D,eAAe;AAAA,QAEf,8BAAC,SAAI,WAAU,6EACZ,oBAAU,IAAI,CAAC,UAAU,MACxB;AAAA,UAAC;AAAA;AAAA,YAEC;AAAA,YACA,WAAW;AAAA,YACX,cAAY;AAAA,YACZ,aAAa;AAAA,YACb,cAAc,CAAC,GAAG,MAAM,UAAU,YAAY,GAAG,CAAC;AAAA;AAAA,UAL7C,GAAG,SAAS,MAAM,IAAI,SAAS,IAAI,IAAI,CAAC;AAAA,QAM/C,CACD,GACH;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,130 @@
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 price_history_chart_exports = {};
21
+ __export(price_history_chart_exports, {
22
+ PriceHistoryChart: () => PriceHistoryChart
23
+ });
24
+ module.exports = __toCommonJS(price_history_chart_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_react = require("react");
27
+ var import_recharts = require("recharts");
28
+ function parsePrice(formatted) {
29
+ return parseFloat(formatted.replace(/[^0-9.]/g, "")) || 0;
30
+ }
31
+ function PriceHistoryChart({ history }) {
32
+ const chartData = (0, import_react.useMemo)(() => {
33
+ const sales = history.filter(
34
+ (e) => e.type === "sale" && e.price?.formatted != null
35
+ );
36
+ if (sales.length < 2) return null;
37
+ const currencyCounts = /* @__PURE__ */ new Map();
38
+ for (const s of sales) {
39
+ const c = s.price.currency ?? "STRK";
40
+ currencyCounts.set(c, (currencyCounts.get(c) ?? 0) + 1);
41
+ }
42
+ const topCurrency = [...currencyCounts.entries()].sort(
43
+ (a, b) => b[1] - a[1]
44
+ )[0][0];
45
+ const points = sales.filter((s) => (s.price.currency ?? "STRK") === topCurrency).map((s) => ({
46
+ date: new Date(
47
+ typeof s.timestamp === "number" ? s.timestamp * 1e3 : s.timestamp
48
+ ).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
49
+ price: parsePrice(s.price.formatted ?? "")
50
+ })).reverse();
51
+ if (points.length < 2) return null;
52
+ return { currency: topCurrency, points };
53
+ }, [history]);
54
+ if (!chartData) {
55
+ return null;
56
+ }
57
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl bg-card/50 p-4 space-y-2", children: [
58
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: [
59
+ "Price history \xB7 ",
60
+ chartData.currency
61
+ ] }),
62
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: 160, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
63
+ import_recharts.LineChart,
64
+ {
65
+ data: chartData.points,
66
+ margin: { top: 4, right: 8, bottom: 0, left: 0 },
67
+ children: [
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
69
+ import_recharts.CartesianGrid,
70
+ {
71
+ strokeDasharray: "3 3",
72
+ stroke: "hsl(var(--border))",
73
+ opacity: 0.5
74
+ }
75
+ ),
76
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
77
+ import_recharts.XAxis,
78
+ {
79
+ dataKey: "date",
80
+ tick: { fontSize: 11, fill: "hsl(var(--muted-foreground))" },
81
+ axisLine: false,
82
+ tickLine: false
83
+ }
84
+ ),
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
86
+ import_recharts.YAxis,
87
+ {
88
+ tick: { fontSize: 11, fill: "hsl(var(--muted-foreground))" },
89
+ axisLine: false,
90
+ tickLine: false,
91
+ width: 48
92
+ }
93
+ ),
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
95
+ import_recharts.Tooltip,
96
+ {
97
+ contentStyle: {
98
+ background: "hsl(var(--background))",
99
+ border: "1px solid hsl(var(--border))",
100
+ borderRadius: "8px",
101
+ fontSize: "12px",
102
+ color: "hsl(var(--foreground))"
103
+ },
104
+ formatter: (value) => [
105
+ `${value} ${chartData.currency}`,
106
+ "Sale price"
107
+ ]
108
+ }
109
+ ),
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
111
+ import_recharts.Line,
112
+ {
113
+ type: "monotone",
114
+ dataKey: "price",
115
+ stroke: "hsl(var(--primary))",
116
+ strokeWidth: 2,
117
+ dot: { fill: "hsl(var(--primary))", r: 3, strokeWidth: 0 },
118
+ activeDot: { r: 5, fill: "hsl(var(--primary))" }
119
+ }
120
+ )
121
+ ]
122
+ }
123
+ ) })
124
+ ] });
125
+ }
126
+ // Annotate the CommonJS export names for ESM import in node:
127
+ 0 && (module.exports = {
128
+ PriceHistoryChart
129
+ });
130
+ //# sourceMappingURL=price-history-chart.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/price-history-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n Tooltip,\n ResponsiveContainer,\n CartesianGrid,\n} from \"recharts\";\nimport type { ApiActivity } from \"@medialane/sdk\";\n\nexport interface PriceHistoryChartProps {\n history: ApiActivity[];\n}\n\nfunction parsePrice(formatted: string): number {\n return parseFloat(formatted.replace(/[^0-9.]/g, \"\")) || 0;\n}\n\nexport function PriceHistoryChart({ history }: PriceHistoryChartProps) {\n const chartData = useMemo(() => {\n const sales = history.filter(\n (e) => e.type === \"sale\" && e.price?.formatted != null\n );\n if (sales.length < 2) return null;\n\n // Pick most common currency to keep Y-axis consistent\n const currencyCounts = new Map<string, number>();\n for (const s of sales) {\n const c = s.price!.currency ?? \"STRK\";\n currencyCounts.set(c, (currencyCounts.get(c) ?? 0) + 1);\n }\n const topCurrency = [...currencyCounts.entries()].sort(\n (a, b) => b[1] - a[1]\n )[0][0];\n\n const points = sales\n .filter((s) => (s.price!.currency ?? \"STRK\") === topCurrency)\n .map((s) => ({\n date: new Date(\n typeof s.timestamp === \"number\" ? s.timestamp * 1000 : s.timestamp\n ).toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" }),\n price: parsePrice(s.price!.formatted ?? \"\"),\n }))\n .reverse(); // oldest → newest left to right\n\n if (points.length < 2) return null;\n return { currency: topCurrency, points };\n }, [history]);\n\n if (!chartData) {\n return null;\n }\n\n return (\n <div className=\"rounded-xl bg-card/50 p-4 space-y-2\">\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n Price history · {chartData.currency}\n </p>\n <ResponsiveContainer width=\"100%\" height={160}>\n <LineChart\n data={chartData.points}\n margin={{ top: 4, right: 8, bottom: 0, left: 0 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"hsl(var(--border))\"\n opacity={0.5}\n />\n <XAxis\n dataKey=\"date\"\n tick={{ fontSize: 11, fill: \"hsl(var(--muted-foreground))\" }}\n axisLine={false}\n tickLine={false}\n />\n <YAxis\n tick={{ fontSize: 11, fill: \"hsl(var(--muted-foreground))\" }}\n axisLine={false}\n tickLine={false}\n width={48}\n />\n <Tooltip\n contentStyle={{\n background: \"hsl(var(--background))\",\n border: \"1px solid hsl(var(--border))\",\n borderRadius: \"8px\",\n fontSize: \"12px\",\n color: \"hsl(var(--foreground))\",\n }}\n formatter={(value) => [\n `${value} ${chartData.currency}`,\n \"Sale price\",\n ]}\n />\n <Line\n type=\"monotone\"\n dataKey=\"price\"\n stroke=\"hsl(var(--primary))\"\n strokeWidth={2}\n dot={{ fill: \"hsl(var(--primary))\", r: 3, strokeWidth: 0 }}\n activeDot={{ r: 5, fill: \"hsl(var(--primary))\" }}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2DM;AAzDN,mBAAwB;AACxB,sBAQO;AAOP,SAAS,WAAW,WAA2B;AAC7C,SAAO,WAAW,UAAU,QAAQ,YAAY,EAAE,CAAC,KAAK;AAC1D;AAEO,SAAS,kBAAkB,EAAE,QAAQ,GAA2B;AACrE,QAAM,gBAAY,sBAAQ,MAAM;AAC9B,UAAM,QAAQ,QAAQ;AAAA,MACpB,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,OAAO,aAAa;AAAA,IACpD;AACA,QAAI,MAAM,SAAS,EAAG,QAAO;AAG7B,UAAM,iBAAiB,oBAAI,IAAoB;AAC/C,eAAW,KAAK,OAAO;AACrB,YAAM,IAAI,EAAE,MAAO,YAAY;AAC/B,qBAAe,IAAI,IAAI,eAAe,IAAI,CAAC,KAAK,KAAK,CAAC;AAAA,IACxD;AACA,UAAM,cAAc,CAAC,GAAG,eAAe,QAAQ,CAAC,EAAE;AAAA,MAChD,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;AAAA,IACtB,EAAE,CAAC,EAAE,CAAC;AAEN,UAAM,SAAS,MACZ,OAAO,CAAC,OAAO,EAAE,MAAO,YAAY,YAAY,WAAW,EAC3D,IAAI,CAAC,OAAO;AAAA,MACX,MAAM,IAAI;AAAA,QACR,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY,MAAO,EAAE;AAAA,MAC3D,EAAE,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,MAChE,OAAO,WAAW,EAAE,MAAO,aAAa,EAAE;AAAA,IAC5C,EAAE,EACD,QAAQ;AAEX,QAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,WAAO,EAAE,UAAU,aAAa,OAAO;AAAA,EACzC,GAAG,CAAC,OAAO,CAAC;AAEZ,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SACE,6CAAC,SAAI,WAAU,uCACb;AAAA,iDAAC,OAAE,WAAU,qEAAoE;AAAA;AAAA,MAC9D,UAAU;AAAA,OAC7B;AAAA,IACA,4CAAC,uCAAoB,OAAM,QAAO,QAAQ,KACxC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,UAAU;AAAA,QAChB,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE;AAAA,QAE/C;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,iBAAgB;AAAA,cAChB,QAAO;AAAA,cACP,SAAS;AAAA;AAAA,UACX;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAM,EAAE,UAAU,IAAI,MAAM,+BAA+B;AAAA,cAC3D,UAAU;AAAA,cACV,UAAU;AAAA;AAAA,UACZ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,EAAE,UAAU,IAAI,MAAM,+BAA+B;AAAA,cAC3D,UAAU;AAAA,cACV,UAAU;AAAA,cACV,OAAO;AAAA;AAAA,UACT;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,cAAc;AAAA,gBACZ,YAAY;AAAA,gBACZ,QAAQ;AAAA,gBACR,cAAc;AAAA,gBACd,UAAU;AAAA,gBACV,OAAO;AAAA,cACT;AAAA,cACA,WAAW,CAAC,UAAU;AAAA,gBACpB,GAAG,KAAK,IAAI,UAAU,QAAQ;AAAA,gBAC9B;AAAA,cACF;AAAA;AAAA,UACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,QAAO;AAAA,cACP,aAAa;AAAA,cACb,KAAK,EAAE,MAAM,uBAAuB,GAAG,GAAG,aAAa,EAAE;AAAA,cACzD,WAAW,EAAE,GAAG,GAAG,MAAM,sBAAsB;AAAA;AAAA,UACjD;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,9 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiActivity } from '@medialane/sdk';
3
+
4
+ interface PriceHistoryChartProps {
5
+ history: ApiActivity[];
6
+ }
7
+ declare function PriceHistoryChart({ history }: PriceHistoryChartProps): react_jsx_runtime.JSX.Element | null;
8
+
9
+ export { PriceHistoryChart, type PriceHistoryChartProps };
@@ -0,0 +1,9 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ApiActivity } from '@medialane/sdk';
3
+
4
+ interface PriceHistoryChartProps {
5
+ history: ApiActivity[];
6
+ }
7
+ declare function PriceHistoryChart({ history }: PriceHistoryChartProps): react_jsx_runtime.JSX.Element | null;
8
+
9
+ export { PriceHistoryChart, type PriceHistoryChartProps };
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from "react";
4
+ import {
5
+ LineChart,
6
+ Line,
7
+ XAxis,
8
+ YAxis,
9
+ Tooltip,
10
+ ResponsiveContainer,
11
+ CartesianGrid
12
+ } from "recharts";
13
+ function parsePrice(formatted) {
14
+ return parseFloat(formatted.replace(/[^0-9.]/g, "")) || 0;
15
+ }
16
+ function PriceHistoryChart({ history }) {
17
+ const chartData = useMemo(() => {
18
+ const sales = history.filter(
19
+ (e) => e.type === "sale" && e.price?.formatted != null
20
+ );
21
+ if (sales.length < 2) return null;
22
+ const currencyCounts = /* @__PURE__ */ new Map();
23
+ for (const s of sales) {
24
+ const c = s.price.currency ?? "STRK";
25
+ currencyCounts.set(c, (currencyCounts.get(c) ?? 0) + 1);
26
+ }
27
+ const topCurrency = [...currencyCounts.entries()].sort(
28
+ (a, b) => b[1] - a[1]
29
+ )[0][0];
30
+ const points = sales.filter((s) => (s.price.currency ?? "STRK") === topCurrency).map((s) => ({
31
+ date: new Date(
32
+ typeof s.timestamp === "number" ? s.timestamp * 1e3 : s.timestamp
33
+ ).toLocaleDateString("en-US", { month: "short", day: "numeric" }),
34
+ price: parsePrice(s.price.formatted ?? "")
35
+ })).reverse();
36
+ if (points.length < 2) return null;
37
+ return { currency: topCurrency, points };
38
+ }, [history]);
39
+ if (!chartData) {
40
+ return null;
41
+ }
42
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-xl bg-card/50 p-4 space-y-2", children: [
43
+ /* @__PURE__ */ jsxs("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: [
44
+ "Price history \xB7 ",
45
+ chartData.currency
46
+ ] }),
47
+ /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: 160, children: /* @__PURE__ */ jsxs(
48
+ LineChart,
49
+ {
50
+ data: chartData.points,
51
+ margin: { top: 4, right: 8, bottom: 0, left: 0 },
52
+ children: [
53
+ /* @__PURE__ */ jsx(
54
+ CartesianGrid,
55
+ {
56
+ strokeDasharray: "3 3",
57
+ stroke: "hsl(var(--border))",
58
+ opacity: 0.5
59
+ }
60
+ ),
61
+ /* @__PURE__ */ jsx(
62
+ XAxis,
63
+ {
64
+ dataKey: "date",
65
+ tick: { fontSize: 11, fill: "hsl(var(--muted-foreground))" },
66
+ axisLine: false,
67
+ tickLine: false
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsx(
71
+ YAxis,
72
+ {
73
+ tick: { fontSize: 11, fill: "hsl(var(--muted-foreground))" },
74
+ axisLine: false,
75
+ tickLine: false,
76
+ width: 48
77
+ }
78
+ ),
79
+ /* @__PURE__ */ jsx(
80
+ Tooltip,
81
+ {
82
+ contentStyle: {
83
+ background: "hsl(var(--background))",
84
+ border: "1px solid hsl(var(--border))",
85
+ borderRadius: "8px",
86
+ fontSize: "12px",
87
+ color: "hsl(var(--foreground))"
88
+ },
89
+ formatter: (value) => [
90
+ `${value} ${chartData.currency}`,
91
+ "Sale price"
92
+ ]
93
+ }
94
+ ),
95
+ /* @__PURE__ */ jsx(
96
+ Line,
97
+ {
98
+ type: "monotone",
99
+ dataKey: "price",
100
+ stroke: "hsl(var(--primary))",
101
+ strokeWidth: 2,
102
+ dot: { fill: "hsl(var(--primary))", r: 3, strokeWidth: 0 },
103
+ activeDot: { r: 5, fill: "hsl(var(--primary))" }
104
+ }
105
+ )
106
+ ]
107
+ }
108
+ ) })
109
+ ] });
110
+ }
111
+ export {
112
+ PriceHistoryChart
113
+ };
114
+ //# sourceMappingURL=price-history-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/price-history-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n Tooltip,\n ResponsiveContainer,\n CartesianGrid,\n} from \"recharts\";\nimport type { ApiActivity } from \"@medialane/sdk\";\n\nexport interface PriceHistoryChartProps {\n history: ApiActivity[];\n}\n\nfunction parsePrice(formatted: string): number {\n return parseFloat(formatted.replace(/[^0-9.]/g, \"\")) || 0;\n}\n\nexport function PriceHistoryChart({ history }: PriceHistoryChartProps) {\n const chartData = useMemo(() => {\n const sales = history.filter(\n (e) => e.type === \"sale\" && e.price?.formatted != null\n );\n if (sales.length < 2) return null;\n\n // Pick most common currency to keep Y-axis consistent\n const currencyCounts = new Map<string, number>();\n for (const s of sales) {\n const c = s.price!.currency ?? \"STRK\";\n currencyCounts.set(c, (currencyCounts.get(c) ?? 0) + 1);\n }\n const topCurrency = [...currencyCounts.entries()].sort(\n (a, b) => b[1] - a[1]\n )[0][0];\n\n const points = sales\n .filter((s) => (s.price!.currency ?? \"STRK\") === topCurrency)\n .map((s) => ({\n date: new Date(\n typeof s.timestamp === \"number\" ? s.timestamp * 1000 : s.timestamp\n ).toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" }),\n price: parsePrice(s.price!.formatted ?? \"\"),\n }))\n .reverse(); // oldest → newest left to right\n\n if (points.length < 2) return null;\n return { currency: topCurrency, points };\n }, [history]);\n\n if (!chartData) {\n return null;\n }\n\n return (\n <div className=\"rounded-xl bg-card/50 p-4 space-y-2\">\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide\">\n Price history · {chartData.currency}\n </p>\n <ResponsiveContainer width=\"100%\" height={160}>\n <LineChart\n data={chartData.points}\n margin={{ top: 4, right: 8, bottom: 0, left: 0 }}\n >\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"hsl(var(--border))\"\n opacity={0.5}\n />\n <XAxis\n dataKey=\"date\"\n tick={{ fontSize: 11, fill: \"hsl(var(--muted-foreground))\" }}\n axisLine={false}\n tickLine={false}\n />\n <YAxis\n tick={{ fontSize: 11, fill: \"hsl(var(--muted-foreground))\" }}\n axisLine={false}\n tickLine={false}\n width={48}\n />\n <Tooltip\n contentStyle={{\n background: \"hsl(var(--background))\",\n border: \"1px solid hsl(var(--border))\",\n borderRadius: \"8px\",\n fontSize: \"12px\",\n color: \"hsl(var(--foreground))\",\n }}\n formatter={(value) => [\n `${value} ${chartData.currency}`,\n \"Sale price\",\n ]}\n />\n <Line\n type=\"monotone\"\n dataKey=\"price\"\n stroke=\"hsl(var(--primary))\"\n strokeWidth={2}\n dot={{ fill: \"hsl(var(--primary))\", r: 3, strokeWidth: 0 }}\n activeDot={{ r: 5, fill: \"hsl(var(--primary))\" }}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n );\n}\n"],"mappings":"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","names":[]}