@medialane/ui 0.104.0 → 0.106.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/asset-collection-bar.cjs +1 -1
- package/dist/components/asset-collection-bar.cjs.map +1 -1
- package/dist/components/asset-collection-bar.js +1 -1
- package/dist/components/asset-collection-bar.js.map +1 -1
- package/dist/components/asset-lightbox.cjs +66 -0
- package/dist/components/asset-lightbox.cjs.map +1 -0
- package/dist/components/asset-lightbox.d.cts +11 -0
- package/dist/components/asset-lightbox.d.ts +11 -0
- package/dist/components/asset-lightbox.js +42 -0
- package/dist/components/asset-lightbox.js.map +1 -0
- package/dist/components/asset-marketplace-panel.cjs +19 -9
- package/dist/components/asset-marketplace-panel.cjs.map +1 -1
- package/dist/components/asset-marketplace-panel.js +19 -9
- package/dist/components/asset-marketplace-panel.js.map +1 -1
- package/dist/components/club-owner-actions.cjs +56 -0
- package/dist/components/club-owner-actions.cjs.map +1 -0
- package/dist/components/club-owner-actions.d.cts +11 -0
- package/dist/components/club-owner-actions.d.ts +11 -0
- package/dist/components/club-owner-actions.js +22 -0
- package/dist/components/club-owner-actions.js.map +1 -0
- package/dist/components/collection-hero-banner.cjs +114 -0
- package/dist/components/collection-hero-banner.cjs.map +1 -0
- package/dist/components/collection-hero-banner.d.cts +26 -0
- package/dist/components/collection-hero-banner.d.ts +26 -0
- package/dist/components/collection-hero-banner.js +90 -0
- package/dist/components/collection-hero-banner.js.map +1 -0
- package/dist/components/create-form-primitives.cjs +61 -0
- package/dist/components/create-form-primitives.cjs.map +1 -0
- package/dist/components/create-form-primitives.d.cts +16 -0
- package/dist/components/create-form-primitives.d.ts +16 -0
- package/dist/components/create-form-primitives.js +36 -0
- package/dist/components/create-form-primitives.js.map +1 -0
- package/dist/components/creation-record.cjs +86 -0
- package/dist/components/creation-record.cjs.map +1 -0
- package/dist/components/creation-record.d.cts +14 -0
- package/dist/components/creation-record.d.ts +14 -0
- package/dist/components/creation-record.js +52 -0
- package/dist/components/creation-record.js.map +1 -0
- package/dist/components/dialog.d.cts +9 -9
- package/dist/components/dialog.d.ts +9 -9
- package/dist/components/ip-type-fields.cjs +307 -0
- package/dist/components/ip-type-fields.cjs.map +1 -0
- package/dist/components/ip-type-fields.d.cts +17 -0
- package/dist/components/ip-type-fields.d.ts +17 -0
- package/dist/components/ip-type-fields.js +293 -0
- package/dist/components/ip-type-fields.js.map +1 -0
- package/dist/components/json-ld.cjs +39 -0
- package/dist/components/json-ld.cjs.map +1 -0
- package/dist/components/json-ld.d.cts +8 -0
- package/dist/components/json-ld.d.ts +8 -0
- package/dist/components/json-ld.js +15 -0
- package/dist/components/json-ld.js.map +1 -0
- package/dist/components/nav-theme-toggle.cjs +66 -0
- package/dist/components/nav-theme-toggle.cjs.map +1 -0
- package/dist/components/nav-theme-toggle.d.cts +9 -0
- package/dist/components/nav-theme-toggle.d.ts +9 -0
- package/dist/components/nav-theme-toggle.js +42 -0
- package/dist/components/nav-theme-toggle.js.map +1 -0
- package/dist/components/order-sort-control.cjs +58 -0
- package/dist/components/order-sort-control.cjs.map +1 -0
- package/dist/components/order-sort-control.d.cts +13 -0
- package/dist/components/order-sort-control.d.ts +13 -0
- package/dist/components/order-sort-control.js +39 -0
- package/dist/components/order-sort-control.js.map +1 -0
- package/dist/components/price-history-chart.cjs +130 -0
- package/dist/components/price-history-chart.cjs.map +1 -0
- package/dist/components/price-history-chart.d.cts +9 -0
- package/dist/components/price-history-chart.d.ts +9 -0
- package/dist/components/price-history-chart.js +114 -0
- package/dist/components/price-history-chart.js.map +1 -0
- package/dist/components/sheet.cjs +160 -0
- package/dist/components/sheet.cjs.map +1 -0
- package/dist/components/sheet.d.cts +30 -0
- package/dist/components/sheet.d.ts +30 -0
- package/dist/components/sheet.js +117 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/textarea.cjs +57 -0
- package/dist/components/textarea.cjs.map +1 -0
- package/dist/components/textarea.d.cts +6 -0
- package/dist/components/textarea.d.ts +6 -0
- package/dist/components/textarea.js +23 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/index.cjs +70 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/format-activity.cjs +143 -0
- package/dist/utils/format-activity.cjs.map +1 -0
- package/dist/utils/format-activity.d.cts +14 -0
- package/dist/utils/format-activity.d.ts +14 -0
- package/dist/utils/format-activity.js +116 -0
- package/dist/utils/format-activity.js.map +1 -0
- package/dist/utils/proxy-body.cjs +60 -0
- package/dist/utils/proxy-body.cjs.map +1 -0
- package/dist/utils/proxy-body.d.cts +22 -0
- package/dist/utils/proxy-body.d.ts +22 -0
- package/dist/utils/proxy-body.js +36 -0
- package/dist/utils/proxy-body.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { useTheme } from "next-themes";
|
|
5
|
+
import { Sun, Moon } from "lucide-react";
|
|
6
|
+
import { cn } from "../utils/cn.js";
|
|
7
|
+
function NavThemeToggle() {
|
|
8
|
+
const { resolvedTheme, setTheme } = useTheme();
|
|
9
|
+
const [mounted, setMounted] = useState(false);
|
|
10
|
+
useEffect(() => setMounted(true), []);
|
|
11
|
+
const isDark = mounted ? resolvedTheme === "dark" : true;
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
"div",
|
|
14
|
+
{
|
|
15
|
+
role: "group",
|
|
16
|
+
"aria-label": "Theme",
|
|
17
|
+
className: "flex items-center gap-0.5 rounded-lg bg-muted/40 p-0.5",
|
|
18
|
+
children: [
|
|
19
|
+
{ key: "light", label: "Light theme", Icon: Sun, active: !isDark },
|
|
20
|
+
{ key: "dark", label: "Dark theme", Icon: Moon, active: isDark }
|
|
21
|
+
].map(({ key, label, Icon, active }) => /* @__PURE__ */ jsx(
|
|
22
|
+
"button",
|
|
23
|
+
{
|
|
24
|
+
type: "button",
|
|
25
|
+
"aria-label": label,
|
|
26
|
+
"aria-pressed": active,
|
|
27
|
+
onClick: () => setTheme(key),
|
|
28
|
+
className: cn(
|
|
29
|
+
"flex h-7 w-7 items-center justify-center rounded-md transition-colors",
|
|
30
|
+
active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground/60 hover:text-foreground"
|
|
31
|
+
),
|
|
32
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" })
|
|
33
|
+
},
|
|
34
|
+
key
|
|
35
|
+
))
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
NavThemeToggle
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=nav-theme-toggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/nav-theme-toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useTheme } from \"next-themes\";\nimport { Sun, Moon } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\n/**\n * Compact Light/Dark segmented toggle for the nav menu footer.\n * Passed to NavCommandMenu via its `footerSlot` prop.\n */\nexport function NavThemeToggle() {\n const { resolvedTheme, setTheme } = useTheme();\n const [mounted, setMounted] = useState(false);\n\n // next-themes can't know the theme until mounted — avoid hydration mismatch.\n useEffect(() => setMounted(true), []);\n\n const isDark = mounted ? resolvedTheme === \"dark\" : true;\n\n return (\n <div\n role=\"group\"\n aria-label=\"Theme\"\n className=\"flex items-center gap-0.5 rounded-lg bg-muted/40 p-0.5\"\n >\n {[\n { key: \"light\", label: \"Light theme\", Icon: Sun, active: !isDark },\n { key: \"dark\", label: \"Dark theme\", Icon: Moon, active: isDark },\n ].map(({ key, label, Icon, active }) => (\n <button\n key={key}\n type=\"button\"\n aria-label={label}\n aria-pressed={active}\n onClick={() => setTheme(key)}\n className={cn(\n \"flex h-7 w-7 items-center justify-center rounded-md transition-colors\",\n active\n ? \"bg-background text-foreground shadow-sm\"\n : \"text-muted-foreground/60 hover:text-foreground\"\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n </button>\n ))}\n </div>\n );\n}\n"],"mappings":";AA2CU;AAzCV,SAAS,WAAW,gBAAgB;AACpC,SAAS,gBAAgB;AACzB,SAAS,KAAK,YAAY;AAC1B,SAAS,UAAU;AAMZ,SAAS,iBAAiB;AAC/B,QAAM,EAAE,eAAe,SAAS,IAAI,SAAS;AAC7C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAG5C,YAAU,MAAM,WAAW,IAAI,GAAG,CAAC,CAAC;AAEpC,QAAM,SAAS,UAAU,kBAAkB,SAAS;AAEpD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAU;AAAA,MAET;AAAA,QACC,EAAE,KAAK,SAAS,OAAO,eAAe,MAAM,KAAK,QAAQ,CAAC,OAAO;AAAA,QACjE,EAAE,KAAK,QAAQ,OAAO,cAAc,MAAM,MAAM,QAAQ,OAAO;AAAA,MACjE,EAAE,IAAI,CAAC,EAAE,KAAK,OAAO,MAAM,OAAO,MAChC;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,cAAY;AAAA,UACZ,gBAAc;AAAA,UACd,SAAS,MAAM,SAAS,GAAG;AAAA,UAC3B,WAAW;AAAA,YACT;AAAA,YACA,SACI,4CACA;AAAA,UACN;AAAA,UAEA,8BAAC,QAAK,WAAU,eAAc;AAAA;AAAA,QAZzB;AAAA,MAaP,CACD;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,58 @@
|
|
|
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 order_sort_control_exports = {};
|
|
21
|
+
__export(order_sort_control_exports, {
|
|
22
|
+
OrderSortControl: () => OrderSortControl,
|
|
23
|
+
sortOrders: () => sortOrders
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(order_sort_control_exports);
|
|
26
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
27
|
+
var import_lucide_react = require("lucide-react");
|
|
28
|
+
var import_select = require("./select.js");
|
|
29
|
+
const LABELS = {
|
|
30
|
+
recent: "Recently listed",
|
|
31
|
+
price_asc: "Price: low to high",
|
|
32
|
+
price_desc: "Price: high to low"
|
|
33
|
+
};
|
|
34
|
+
function sortOrders(orders, sort) {
|
|
35
|
+
if (sort === "recent") return orders;
|
|
36
|
+
const withPrice = orders.filter((o) => o.price.raw != null);
|
|
37
|
+
const withoutPrice = orders.filter((o) => o.price.raw == null);
|
|
38
|
+
const sorted = [...withPrice].sort((a, b) => {
|
|
39
|
+
const diff = BigInt(a.price.raw) - BigInt(b.price.raw);
|
|
40
|
+
return sort === "price_asc" ? diff < 0n ? -1 : diff > 0n ? 1 : 0 : diff > 0n ? -1 : diff < 0n ? 1 : 0;
|
|
41
|
+
});
|
|
42
|
+
return [...sorted, ...withoutPrice];
|
|
43
|
+
}
|
|
44
|
+
function OrderSortControl({ value, onChange }) {
|
|
45
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value, onValueChange: (v) => onChange(v), children: [
|
|
46
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.SelectTrigger, { className: "w-[180px] h-9 text-xs gap-1.5", children: [
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowDownUp, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {})
|
|
49
|
+
] }),
|
|
50
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectContent, { children: Object.keys(LABELS).map((k) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: k, className: "text-xs", children: LABELS[k] }, k)) })
|
|
51
|
+
] });
|
|
52
|
+
}
|
|
53
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
54
|
+
0 && (module.exports = {
|
|
55
|
+
OrderSortControl,
|
|
56
|
+
sortOrders
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=order-sort-control.cjs.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":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCM;AA9BN,0BAA4B;AAE5B,oBAEO;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,6CAAC,wBAAO,OAAc,eAAe,CAAC,MAAM,SAAS,CAAc,GACjE;AAAA,iDAAC,+BAAc,WAAU,iCACvB;AAAA,kDAAC,mCAAY,WAAU,qCAAoC;AAAA,MAC3D,4CAAC,6BAAY;AAAA,OACf;AAAA,IACA,4CAAC,+BACG,iBAAO,KAAK,MAAM,EAAkB,IAAI,CAAC,MACzC,4CAAC,4BAAmB,OAAO,GAAG,WAAU,WAAW,iBAAO,CAAC,KAA1C,CAA4C,CAC9D,GACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -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,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":"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","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":[]}
|
|
@@ -0,0 +1,160 @@
|
|
|
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 sheet_exports = {};
|
|
31
|
+
__export(sheet_exports, {
|
|
32
|
+
Sheet: () => Sheet,
|
|
33
|
+
SheetClose: () => SheetClose,
|
|
34
|
+
SheetContent: () => SheetContent,
|
|
35
|
+
SheetDescription: () => SheetDescription,
|
|
36
|
+
SheetFooter: () => SheetFooter,
|
|
37
|
+
SheetHeader: () => SheetHeader,
|
|
38
|
+
SheetOverlay: () => SheetOverlay,
|
|
39
|
+
SheetPortal: () => SheetPortal,
|
|
40
|
+
SheetTitle: () => SheetTitle,
|
|
41
|
+
SheetTrigger: () => SheetTrigger
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(sheet_exports);
|
|
44
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
45
|
+
var React = __toESM(require("react"), 1);
|
|
46
|
+
var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
47
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
48
|
+
var import_lucide_react = require("lucide-react");
|
|
49
|
+
var import_cn = require("../utils/cn.js");
|
|
50
|
+
const Sheet = SheetPrimitive.Root;
|
|
51
|
+
const SheetTrigger = SheetPrimitive.Trigger;
|
|
52
|
+
const SheetClose = SheetPrimitive.Close;
|
|
53
|
+
const SheetPortal = SheetPrimitive.Portal;
|
|
54
|
+
const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
55
|
+
SheetPrimitive.Overlay,
|
|
56
|
+
{
|
|
57
|
+
className: (0, import_cn.cn)(
|
|
58
|
+
"fixed inset-0 z-50 backdrop-blur-[48px] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
59
|
+
className
|
|
60
|
+
),
|
|
61
|
+
...props,
|
|
62
|
+
ref
|
|
63
|
+
}
|
|
64
|
+
));
|
|
65
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
66
|
+
const sheetVariants = (0, import_class_variance_authority.cva)(
|
|
67
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
68
|
+
{
|
|
69
|
+
variants: {
|
|
70
|
+
side: {
|
|
71
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
72
|
+
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
73
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
74
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
defaultVariants: {
|
|
78
|
+
side: "right"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
const SheetContent = React.forwardRef(({ side = "right", className, children, overlayClassName, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetPortal, { children: [
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SheetOverlay, { className: overlayClassName }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
85
|
+
SheetPrimitive.Content,
|
|
86
|
+
{
|
|
87
|
+
ref,
|
|
88
|
+
className: (0, import_cn.cn)(sheetVariants({ side }), className),
|
|
89
|
+
...props,
|
|
90
|
+
children: [
|
|
91
|
+
children,
|
|
92
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
|
|
93
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-4 w-4" }),
|
|
94
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: "Close" })
|
|
95
|
+
] })
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
] }));
|
|
100
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
101
|
+
const SheetHeader = ({
|
|
102
|
+
className,
|
|
103
|
+
...props
|
|
104
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
105
|
+
"div",
|
|
106
|
+
{
|
|
107
|
+
className: (0, import_cn.cn)(
|
|
108
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
109
|
+
className
|
|
110
|
+
),
|
|
111
|
+
...props
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
SheetHeader.displayName = "SheetHeader";
|
|
115
|
+
const SheetFooter = ({
|
|
116
|
+
className,
|
|
117
|
+
...props
|
|
118
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
119
|
+
"div",
|
|
120
|
+
{
|
|
121
|
+
className: (0, import_cn.cn)(
|
|
122
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
123
|
+
className
|
|
124
|
+
),
|
|
125
|
+
...props
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
SheetFooter.displayName = "SheetFooter";
|
|
129
|
+
const SheetTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
130
|
+
SheetPrimitive.Title,
|
|
131
|
+
{
|
|
132
|
+
ref,
|
|
133
|
+
className: (0, import_cn.cn)("text-lg font-semibold text-foreground", className),
|
|
134
|
+
...props
|
|
135
|
+
}
|
|
136
|
+
));
|
|
137
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
138
|
+
const SheetDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
139
|
+
SheetPrimitive.Description,
|
|
140
|
+
{
|
|
141
|
+
ref,
|
|
142
|
+
className: (0, import_cn.cn)("text-sm text-muted-foreground", className),
|
|
143
|
+
...props
|
|
144
|
+
}
|
|
145
|
+
));
|
|
146
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
147
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
148
|
+
0 && (module.exports = {
|
|
149
|
+
Sheet,
|
|
150
|
+
SheetClose,
|
|
151
|
+
SheetContent,
|
|
152
|
+
SheetDescription,
|
|
153
|
+
SheetFooter,
|
|
154
|
+
SheetHeader,
|
|
155
|
+
SheetOverlay,
|
|
156
|
+
SheetPortal,
|
|
157
|
+
SheetTitle,
|
|
158
|
+
SheetTrigger
|
|
159
|
+
});
|
|
160
|
+
//# sourceMappingURL=sheet.cjs.map
|