@loafmarkets/ui 0.0.5 → 0.0.7
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/index.d.mts +22 -17
- package/dist/index.d.ts +22 -17
- package/dist/index.js +544 -319
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +545 -320
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -168,8 +168,8 @@ var PortfolioSummary = React5__namespace.forwardRef(
|
|
|
168
168
|
onResetAccount,
|
|
169
169
|
positionsHeading = "Current Positions",
|
|
170
170
|
emptyPositionsText = "No positions yet. Start trading to build your portfolio!",
|
|
171
|
-
formatCurrency = defaultFormatCurrency,
|
|
172
|
-
formatPercent = defaultFormatPercent,
|
|
171
|
+
formatCurrency: formatCurrency2 = defaultFormatCurrency,
|
|
172
|
+
formatPercent: formatPercent2 = defaultFormatPercent,
|
|
173
173
|
formatSignedCurrency = defaultFormatSignedCurrency,
|
|
174
174
|
className,
|
|
175
175
|
children,
|
|
@@ -206,15 +206,15 @@ var PortfolioSummary = React5__namespace.forwardRef(
|
|
|
206
206
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
207
207
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
208
208
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Available Cash" }),
|
|
209
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children:
|
|
209
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children: formatCurrency2(availableCash) })
|
|
210
210
|
] }),
|
|
211
211
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
212
212
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Portfolio Value" }),
|
|
213
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children:
|
|
213
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children: formatCurrency2(portfolioValue) })
|
|
214
214
|
] }),
|
|
215
215
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
216
216
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Total Return" }),
|
|
217
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-1 text-[1.25rem] font-semibold", totalReturnClassName), children:
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-1 text-[1.25rem] font-semibold", totalReturnClassName), children: formatPercent2(totalReturnPercent) })
|
|
218
218
|
] }),
|
|
219
219
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
220
220
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Unrealized P&L" }),
|
|
@@ -304,6 +304,7 @@ function HousePositionSlider({
|
|
|
304
304
|
pendingOrders = [],
|
|
305
305
|
defaultOrderType = "market",
|
|
306
306
|
orderbook,
|
|
307
|
+
ownershipPercentOverride,
|
|
307
308
|
onConfirmOrder,
|
|
308
309
|
className,
|
|
309
310
|
...props
|
|
@@ -314,6 +315,7 @@ function HousePositionSlider({
|
|
|
314
315
|
const [deltaTokensBuy, setDeltaTokensBuy] = React5__namespace.useState(0);
|
|
315
316
|
const [deltaTokensSell, setDeltaTokensSell] = React5__namespace.useState(0);
|
|
316
317
|
const [isDragging, setIsDragging] = React5__namespace.useState(false);
|
|
318
|
+
const [visualTargetPct, setVisualTargetPct] = React5__namespace.useState(null);
|
|
317
319
|
const [orderType, setOrderType] = React5__namespace.useState(defaultOrderType);
|
|
318
320
|
const [limitPrice, setLimitPrice] = React5__namespace.useState(currentPrice);
|
|
319
321
|
const [limitPriceInput, setLimitPriceInput] = React5__namespace.useState(currentPrice.toFixed(2));
|
|
@@ -335,9 +337,8 @@ function HousePositionSlider({
|
|
|
335
337
|
const effectiveAvailableCash = Math.max(0, availableCash - pendingBuyValue);
|
|
336
338
|
const effectiveTokensHeld = Math.max(0, tokensHeld - pendingSellTokens);
|
|
337
339
|
const holdingsValue = tokensHeld * effectivePrice;
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
-
const baselinePct = sliderTotalCapacity <= 0 ? 0 : sliderHoldingsValue / sliderTotalCapacity * 100;
|
|
340
|
+
const safeTotalTokens = totalTokens > 0 ? totalTokens : 1;
|
|
341
|
+
const baselineOwnershipActual = clamp(effectiveTokensHeld / safeTotalTokens * 100, 0, 100);
|
|
341
342
|
let deltaTokens = 0;
|
|
342
343
|
let deltaValue = 0;
|
|
343
344
|
let marketAvgPrice = null;
|
|
@@ -383,29 +384,21 @@ function HousePositionSlider({
|
|
|
383
384
|
}
|
|
384
385
|
targetTokens = tokensHeld + deltaTokens;
|
|
385
386
|
targetValue = targetTokens * effectivePrice;
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
if (buyTrackingMode === "dollars") {
|
|
389
|
-
const notional = Math.min(Math.max(0, deltaDollars), effectiveAvailableCash);
|
|
390
|
-
return notional;
|
|
391
|
-
}
|
|
392
|
-
const tokensPlanned = Math.max(0, deltaTokensBuy);
|
|
393
|
-
const referencePrice = orderType === "market" ? currentPrice || limitPriceSafe : limitPriceSafe;
|
|
394
|
-
return Math.min(tokensPlanned * referencePrice, effectiveAvailableCash);
|
|
395
|
-
}
|
|
396
|
-
if (orderMode === "sell") {
|
|
397
|
-
const tokensToSell = Math.abs(Math.min(0, deltaTokensSell));
|
|
398
|
-
const sellValue = tokensToSell * effectivePrice;
|
|
399
|
-
return -Math.min(sellValue, sliderHoldingsValue);
|
|
400
|
-
}
|
|
401
|
-
return 0;
|
|
402
|
-
})();
|
|
403
|
-
const sliderTargetValue = clamp(sliderHoldingsValue + plannedDeltaValue, 0, sliderTotalCapacity);
|
|
404
|
-
const targetPct = sliderTotalCapacity <= 0 ? 0 : sliderTargetValue / sliderTotalCapacity * 100;
|
|
387
|
+
const sliderTargetTokens = clamp(effectiveTokensHeld + deltaTokens, 0, safeTotalTokens);
|
|
388
|
+
const normalizedTargetPct = sliderTargetTokens / safeTotalTokens * 100;
|
|
405
389
|
const isIncrease = orderMode === "buy";
|
|
406
390
|
const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
|
|
407
|
-
const currentOwnership = totalTokens <= 0 ? 0 : tokensHeld / totalTokens * 100;
|
|
408
|
-
const targetOwnership = totalTokens <= 0 ? 0 : targetTokens / totalTokens * 100;
|
|
391
|
+
const currentOwnership = totalTokens <= 0 ? 0 : clamp(tokensHeld / totalTokens * 100, 0, 100);
|
|
392
|
+
const targetOwnership = totalTokens <= 0 ? 0 : clamp(targetTokens / totalTokens * 100, 0, 100);
|
|
393
|
+
const ownershipOverrideValue = typeof ownershipPercentOverride === "number" && Number.isFinite(ownershipPercentOverride) ? clamp(ownershipPercentOverride, 0, 100) : null;
|
|
394
|
+
const ownershipShift = ownershipOverrideValue != null ? ownershipOverrideValue - baselineOwnershipActual : 0;
|
|
395
|
+
const baselinePct = clamp(ownershipOverrideValue ?? baselineOwnershipActual, 0, 100);
|
|
396
|
+
const impliedTargetPct = clamp(normalizedTargetPct + ownershipShift, 0, 100);
|
|
397
|
+
const displayTargetPct = visualTargetPct ?? impliedTargetPct;
|
|
398
|
+
const targetPct = displayTargetPct;
|
|
399
|
+
const displayCurrentOwnership = clamp(ownershipOverrideValue ?? currentOwnership, 0, 100);
|
|
400
|
+
const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
|
|
401
|
+
const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
|
|
409
402
|
const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
|
|
410
403
|
const resetOrder = React5__namespace.useCallback(() => {
|
|
411
404
|
setOrderMode("none");
|
|
@@ -413,6 +406,7 @@ function HousePositionSlider({
|
|
|
413
406
|
setDeltaDollars(0);
|
|
414
407
|
setDeltaTokensBuy(0);
|
|
415
408
|
setDeltaTokensSell(0);
|
|
409
|
+
setVisualTargetPct(null);
|
|
416
410
|
}, []);
|
|
417
411
|
const updateOrderFromTargetValue = React5__namespace.useCallback(
|
|
418
412
|
(newTargetValue) => {
|
|
@@ -443,6 +437,7 @@ function HousePositionSlider({
|
|
|
443
437
|
const nextOwnership = clamp(newOwnershipPercent, 0, 100);
|
|
444
438
|
const newTargetTokens = nextOwnership / 100 * totalTokens;
|
|
445
439
|
updateOrderFromTargetValue(newTargetTokens * effectivePrice);
|
|
440
|
+
setVisualTargetPct(nextOwnership);
|
|
446
441
|
},
|
|
447
442
|
[effectivePrice, totalTokens, updateOrderFromTargetValue]
|
|
448
443
|
);
|
|
@@ -475,12 +470,14 @@ function HousePositionSlider({
|
|
|
475
470
|
const magnitude = Math.min(Math.abs(normalized), 1);
|
|
476
471
|
if (magnitude < 0.02) {
|
|
477
472
|
resetOrder();
|
|
473
|
+
setVisualTargetPct(null);
|
|
478
474
|
return;
|
|
479
475
|
}
|
|
480
476
|
if (normalized > 0) {
|
|
481
477
|
const notional = clamp(magnitude * effectiveAvailableCash, 0, effectiveAvailableCash);
|
|
482
478
|
if (notional <= 0) {
|
|
483
479
|
resetOrder();
|
|
480
|
+
setVisualTargetPct(null);
|
|
484
481
|
return;
|
|
485
482
|
}
|
|
486
483
|
setOrderMode("buy");
|
|
@@ -488,12 +485,14 @@ function HousePositionSlider({
|
|
|
488
485
|
setDeltaDollars(notional);
|
|
489
486
|
setDeltaTokensBuy(0);
|
|
490
487
|
setDeltaTokensSell(0);
|
|
488
|
+
setVisualTargetPct(clamp(pct, 0, 100));
|
|
491
489
|
return;
|
|
492
490
|
}
|
|
493
491
|
if (normalized < 0) {
|
|
494
492
|
const tokensToSell = clamp(magnitude * effectiveTokensHeld, 0, effectiveTokensHeld);
|
|
495
493
|
if (tokensToSell <= 0) {
|
|
496
494
|
resetOrder();
|
|
495
|
+
setVisualTargetPct(null);
|
|
497
496
|
return;
|
|
498
497
|
}
|
|
499
498
|
setOrderMode("sell");
|
|
@@ -501,9 +500,11 @@ function HousePositionSlider({
|
|
|
501
500
|
setDeltaTokensSell(-tokensToSell);
|
|
502
501
|
setDeltaDollars(0);
|
|
503
502
|
setDeltaTokensBuy(0);
|
|
503
|
+
setVisualTargetPct(clamp(pct, 0, 100));
|
|
504
504
|
return;
|
|
505
505
|
}
|
|
506
506
|
resetOrder();
|
|
507
|
+
setVisualTargetPct(null);
|
|
507
508
|
},
|
|
508
509
|
[effectiveAvailableCash, effectiveTokensHeld, resetOrder]
|
|
509
510
|
);
|
|
@@ -666,19 +667,19 @@ function HousePositionSlider({
|
|
|
666
667
|
" Ownership"
|
|
667
668
|
] }),
|
|
668
669
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-white", children: [
|
|
669
|
-
|
|
670
|
+
displayCurrentOwnership.toFixed(2),
|
|
670
671
|
"%",
|
|
671
672
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1.5 text-white/50", children: "\u2192" }),
|
|
672
673
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
673
674
|
"input",
|
|
674
675
|
{
|
|
675
676
|
type: "text",
|
|
676
|
-
value: ownershipInput ||
|
|
677
|
+
value: ownershipInput || displayTargetOwnership.toFixed(2),
|
|
677
678
|
onChange: (e) => {
|
|
678
679
|
const val = e.target.value;
|
|
679
680
|
if (val === "" || /^[0-9]*\.?[0-9]*$/.test(val)) setOwnershipInput(val);
|
|
680
681
|
},
|
|
681
|
-
onFocus: () => setOwnershipInput(
|
|
682
|
+
onFocus: () => setOwnershipInput(displayTargetOwnership.toFixed(2)),
|
|
682
683
|
onBlur: () => {
|
|
683
684
|
const num = Number.parseFloat(ownershipInput);
|
|
684
685
|
if (Number.isFinite(num)) updateOrderFromOwnership(num);
|
|
@@ -689,7 +690,7 @@ function HousePositionSlider({
|
|
|
689
690
|
},
|
|
690
691
|
className: cn(
|
|
691
692
|
"w-[70px] rounded-[4px] border bg-white/10 px-2 py-1 text-right font-semibold outline-none",
|
|
692
|
-
|
|
693
|
+
displayTargetOwnership >= displayCurrentOwnership ? "border-[rgba(14,203,129,0.3)] text-[#0ecb81] focus:border-[#0ecb81]" : "border-[rgba(246,70,93,0.3)] text-[#f6465d] focus:border-[#f6465d]"
|
|
693
694
|
)
|
|
694
695
|
}
|
|
695
696
|
)
|
|
@@ -840,6 +841,9 @@ function DepthRow({
|
|
|
840
841
|
] });
|
|
841
842
|
}
|
|
842
843
|
var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
844
|
+
var LEVEL_ROWS_VISIBLE = 6;
|
|
845
|
+
var DEPTH_ROW_HEIGHT_PX = 34;
|
|
846
|
+
var SECTION_HEIGHT = LEVEL_ROWS_VISIBLE * DEPTH_ROW_HEIGHT_PX;
|
|
843
847
|
var Orderbook = React5__namespace.forwardRef(
|
|
844
848
|
({
|
|
845
849
|
asks,
|
|
@@ -980,18 +984,25 @@ var Orderbook = React5__namespace.forwardRef(
|
|
|
980
984
|
] }, `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`)) })
|
|
981
985
|
}
|
|
982
986
|
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
983
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
984
|
-
|
|
987
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
988
|
+
"div",
|
|
985
989
|
{
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
990
|
+
className: "divide-y divide-white/5 overflow-y-auto",
|
|
991
|
+
style: { height: `${SECTION_HEIGHT}px`, scrollbarGutter: "stable" },
|
|
992
|
+
children: asks.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
993
|
+
DepthRow,
|
|
994
|
+
{
|
|
995
|
+
side: "ask",
|
|
996
|
+
price: l.price,
|
|
997
|
+
amount: l.amount,
|
|
998
|
+
depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
|
|
999
|
+
precision,
|
|
1000
|
+
amountPrecision
|
|
1001
|
+
},
|
|
1002
|
+
`ask-${idx}-${l.price}-${l.amount}`
|
|
1003
|
+
))
|
|
1004
|
+
}
|
|
1005
|
+
),
|
|
995
1006
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
|
|
996
1007
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
|
|
997
1008
|
"$",
|
|
@@ -1004,18 +1015,25 @@ var Orderbook = React5__namespace.forwardRef(
|
|
|
1004
1015
|
] }),
|
|
1005
1016
|
/* @__PURE__ */ jsxRuntime.jsx("div", {})
|
|
1006
1017
|
] }),
|
|
1007
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1008
|
-
|
|
1018
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1019
|
+
"div",
|
|
1009
1020
|
{
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1021
|
+
className: "divide-y divide-white/5 overflow-y-auto",
|
|
1022
|
+
style: { height: `${SECTION_HEIGHT}px`, scrollbarGutter: "stable" },
|
|
1023
|
+
children: bids.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1024
|
+
DepthRow,
|
|
1025
|
+
{
|
|
1026
|
+
side: "bid",
|
|
1027
|
+
price: l.price,
|
|
1028
|
+
amount: l.amount,
|
|
1029
|
+
depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
|
|
1030
|
+
precision,
|
|
1031
|
+
amountPrecision
|
|
1032
|
+
},
|
|
1033
|
+
`bid-${idx}-${l.price}-${l.amount}`
|
|
1034
|
+
))
|
|
1035
|
+
}
|
|
1036
|
+
)
|
|
1019
1037
|
] })
|
|
1020
1038
|
] })
|
|
1021
1039
|
]
|
|
@@ -1117,132 +1135,208 @@ var PropertyTour = React5__namespace.forwardRef(
|
|
|
1117
1135
|
}
|
|
1118
1136
|
);
|
|
1119
1137
|
PropertyTour.displayName = "PropertyTour";
|
|
1120
|
-
var
|
|
1138
|
+
var ITEMS_PER_PAGE = 4;
|
|
1139
|
+
var ROW_HEIGHT_PX = 86;
|
|
1140
|
+
var ensureAnimationsInjected = () => {
|
|
1141
|
+
if (typeof document === "undefined") return;
|
|
1142
|
+
if (document.getElementById("property-news-updates-animations")) return;
|
|
1143
|
+
const style = document.createElement("style");
|
|
1144
|
+
style.id = "property-news-updates-animations";
|
|
1145
|
+
style.textContent = `
|
|
1146
|
+
@keyframes propertyNewsPulse {
|
|
1147
|
+
0% { opacity: 0.6; transform: scale(0.9); }
|
|
1148
|
+
50% { opacity: 1; transform: scale(1); }
|
|
1149
|
+
100% { opacity: 0.6; transform: scale(0.9); }
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
@keyframes propertyNewsSlideIn {
|
|
1153
|
+
from { transform: translateY(-6px); opacity: 0; }
|
|
1154
|
+
to { transform: translateY(0); opacity: 1; }
|
|
1155
|
+
}
|
|
1156
|
+
`;
|
|
1157
|
+
document.head.appendChild(style);
|
|
1158
|
+
};
|
|
1159
|
+
var categoryStyles = {
|
|
1121
1160
|
property: {
|
|
1122
1161
|
label: "Property Update",
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
pillColor: "#f8d12f",
|
|
1127
|
-
icon: lucideReact.Building2
|
|
1162
|
+
backgroundColor: "rgba(14, 203, 129, 0.15)",
|
|
1163
|
+
borderColor: "rgba(14, 203, 129, 0.45)",
|
|
1164
|
+
color: "#0ecb81"
|
|
1128
1165
|
},
|
|
1129
1166
|
market: {
|
|
1130
|
-
label: "Market
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
pillColor: "#0ecb81",
|
|
1135
|
-
icon: lucideReact.LineChart
|
|
1136
|
-
},
|
|
1137
|
-
portfolio: {
|
|
1138
|
-
label: "Portfolio Signal",
|
|
1139
|
-
accent: "#6c8cff",
|
|
1140
|
-
pillBg: "rgba(108, 140, 255, 0.12)",
|
|
1141
|
-
pillBorder: "rgba(108, 140, 255, 0.45)",
|
|
1142
|
-
pillColor: "#c9d5ff",
|
|
1143
|
-
icon: lucideReact.Sparkles
|
|
1167
|
+
label: "Market News",
|
|
1168
|
+
backgroundColor: "rgba(248, 209, 47, 0.15)",
|
|
1169
|
+
borderColor: "rgba(248, 209, 47, 0.45)",
|
|
1170
|
+
color: "#f8d12f"
|
|
1144
1171
|
}
|
|
1145
1172
|
};
|
|
1146
|
-
var getTypeMeta = (type) => {
|
|
1147
|
-
if (!type) return TYPE_META.property;
|
|
1148
|
-
const key = type;
|
|
1149
|
-
if (key in TYPE_META) return TYPE_META[key];
|
|
1150
|
-
return {
|
|
1151
|
-
label: type.toString(),
|
|
1152
|
-
accent: "#f5f5f5",
|
|
1153
|
-
pillBg: "rgba(255,255,255,0.08)",
|
|
1154
|
-
pillBorder: "rgba(255,255,255,0.25)",
|
|
1155
|
-
pillColor: "#ffffff",
|
|
1156
|
-
icon: lucideReact.Newspaper
|
|
1157
|
-
};
|
|
1158
|
-
};
|
|
1159
1173
|
var formatDate = (value) => {
|
|
1160
|
-
|
|
1161
|
-
if (Number.isNaN(
|
|
1162
|
-
return
|
|
1174
|
+
if (typeof value === "string") return value;
|
|
1175
|
+
if (!(value instanceof Date) || Number.isNaN(value.getTime())) return "";
|
|
1176
|
+
return value.toLocaleDateString(void 0, {
|
|
1163
1177
|
month: "short",
|
|
1164
1178
|
day: "numeric",
|
|
1165
1179
|
year: "numeric"
|
|
1166
1180
|
});
|
|
1167
1181
|
};
|
|
1168
1182
|
var PropertyNewsUpdates = React5__namespace.forwardRef(
|
|
1169
|
-
({
|
|
1183
|
+
({
|
|
1184
|
+
className,
|
|
1185
|
+
heading = "Property News & Headlines",
|
|
1186
|
+
subheading,
|
|
1187
|
+
items,
|
|
1188
|
+
emptyState,
|
|
1189
|
+
highlightFirst = true,
|
|
1190
|
+
...props
|
|
1191
|
+
}, ref) => {
|
|
1192
|
+
const [page, setPage] = React5__namespace.useState(0);
|
|
1193
|
+
React5__namespace.useEffect(() => {
|
|
1194
|
+
ensureAnimationsInjected();
|
|
1195
|
+
}, []);
|
|
1170
1196
|
const hasItems = Array.isArray(items) && items.length > 0;
|
|
1197
|
+
const totalPages = React5__namespace.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
|
|
1198
|
+
React5__namespace.useEffect(() => {
|
|
1199
|
+
setPage((prev) => Math.min(prev, totalPages - 1));
|
|
1200
|
+
}, [totalPages]);
|
|
1201
|
+
const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
|
|
1171
1202
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1172
1203
|
"div",
|
|
1173
1204
|
{
|
|
1174
1205
|
ref,
|
|
1175
1206
|
className: cn(
|
|
1176
|
-
"w-full max-w-[
|
|
1207
|
+
"w-full max-w-[840px] rounded-2xl border border-white/10 bg-[#0b0e10] p-5 text-white shadow-[0_20px_40px_rgba(0,0,0,0.35)]",
|
|
1177
1208
|
className
|
|
1178
1209
|
),
|
|
1179
1210
|
...props,
|
|
1180
1211
|
children: [
|
|
1181
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1182
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const Icon = meta.icon;
|
|
1188
|
-
const key = item.id ?? `${item.title}-${index}`;
|
|
1189
|
-
const content = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1212
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1213
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1214
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold text-white", children: heading }),
|
|
1215
|
+
subheading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white/60", children: subheading }) : null
|
|
1216
|
+
] }),
|
|
1217
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1190
1218
|
"div",
|
|
1191
1219
|
{
|
|
1192
|
-
className: "
|
|
1220
|
+
className: "inline-flex items-center font-semibold uppercase text-emerald-300",
|
|
1221
|
+
style: { gap: "0.35rem", fontSize: "0.8rem", letterSpacing: "0.15em" },
|
|
1193
1222
|
children: [
|
|
1194
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
{
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-5 w-5" })
|
|
1205
|
-
}
|
|
1206
|
-
),
|
|
1207
|
-
index !== items.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 h-full w-px flex-1 bg-white/10" }) : null
|
|
1208
|
-
] }),
|
|
1209
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col", children: [
|
|
1210
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
1211
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.7rem] font-semibold uppercase tracking-[0.3em]", style: { color: meta.accent }, children: meta.label }),
|
|
1212
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center text-xs text-white/60", children: [
|
|
1213
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarDays, { className: "mr-1 h-3.5 w-3.5" }),
|
|
1214
|
-
formatDate(item.date)
|
|
1215
|
-
] })
|
|
1216
|
-
] }),
|
|
1217
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-base font-semibold leading-snug", children: item.title }),
|
|
1218
|
-
item.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-white/65", children: item.description }) : null,
|
|
1219
|
-
(item.href || item.onAction) && item.actionLabel ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1220
|
-
"button",
|
|
1221
|
-
{
|
|
1222
|
-
type: "button",
|
|
1223
|
-
className: "group mt-3 inline-flex items-center gap-1 text-sm font-semibold text-white transition hover:text-white/80",
|
|
1224
|
-
onClick: () => {
|
|
1225
|
-
if (item.href) {
|
|
1226
|
-
window?.open?.(item.href, "_blank", "noopener,noreferrer");
|
|
1227
|
-
}
|
|
1228
|
-
item.onAction?.(item);
|
|
1229
|
-
},
|
|
1230
|
-
children: [
|
|
1231
|
-
item.actionLabel,
|
|
1232
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { className: "h-4 w-4 transition group-hover:translate-x-0.5 group-hover:-translate-y-0.5" })
|
|
1233
|
-
]
|
|
1223
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1224
|
+
"span",
|
|
1225
|
+
{
|
|
1226
|
+
style: {
|
|
1227
|
+
display: "inline-block",
|
|
1228
|
+
width: "6px",
|
|
1229
|
+
height: "6px",
|
|
1230
|
+
borderRadius: "50%",
|
|
1231
|
+
backgroundColor: "#34d399",
|
|
1232
|
+
animation: "propertyNewsPulse 2s infinite"
|
|
1234
1233
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1234
|
+
}
|
|
1235
|
+
),
|
|
1236
|
+
"LIVE"
|
|
1237
1237
|
]
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1238
|
+
}
|
|
1239
|
+
)
|
|
1240
|
+
] }),
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1242
|
+
"div",
|
|
1243
|
+
{
|
|
1244
|
+
className: "mt-4 flex flex-col gap-3",
|
|
1245
|
+
style: { minHeight: `${ITEMS_PER_PAGE * ROW_HEIGHT_PX}px` },
|
|
1246
|
+
children: hasItems ? paginatedItems.map((item, index) => {
|
|
1247
|
+
const absoluteIndex = page * ITEMS_PER_PAGE + index;
|
|
1248
|
+
const key = item.displayId ?? item.id ?? `${item.title}-${absoluteIndex}`;
|
|
1249
|
+
const styles = categoryStyles[item.type] ?? categoryStyles.market;
|
|
1250
|
+
const dateLabel = item.isNew ?? (highlightFirst && absoluteIndex === 0) ? "Just now" : typeof item.date === "string" && item.date.trim().length > 0 ? item.date : formatDate(item.date);
|
|
1251
|
+
const isHighlighted = item.isNew ?? (highlightFirst && absoluteIndex === 0);
|
|
1252
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1253
|
+
"div",
|
|
1254
|
+
{
|
|
1255
|
+
style: {
|
|
1256
|
+
padding: "0.75rem",
|
|
1257
|
+
borderRadius: "6px",
|
|
1258
|
+
backgroundColor: isHighlighted ? "rgba(14, 203, 129, 0.1)" : "transparent",
|
|
1259
|
+
border: "1px solid transparent",
|
|
1260
|
+
transition: "background-color 0.2s",
|
|
1261
|
+
animation: item.isNew ? "propertyNewsSlideIn 0.5s ease-out" : void 0
|
|
1262
|
+
},
|
|
1263
|
+
children: [
|
|
1264
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.9375rem", fontWeight: 500, marginBottom: "0.35rem" }, children: item.title }),
|
|
1265
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1266
|
+
"div",
|
|
1267
|
+
{
|
|
1268
|
+
style: {
|
|
1269
|
+
display: "flex",
|
|
1270
|
+
justifyContent: "space-between",
|
|
1271
|
+
alignItems: "center",
|
|
1272
|
+
fontSize: "0.75rem",
|
|
1273
|
+
color: "#b5b8c5"
|
|
1274
|
+
},
|
|
1275
|
+
children: [
|
|
1276
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: isHighlighted ? "#0ecb81" : "inherit" }, children: dateLabel }),
|
|
1277
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1278
|
+
"span",
|
|
1279
|
+
{
|
|
1280
|
+
style: {
|
|
1281
|
+
padding: "0.25rem 0.6rem",
|
|
1282
|
+
borderRadius: "4px",
|
|
1283
|
+
border: `1px solid ${styles.borderColor}`,
|
|
1284
|
+
backgroundColor: styles.backgroundColor,
|
|
1285
|
+
color: styles.color,
|
|
1286
|
+
fontSize: "0.68rem",
|
|
1287
|
+
fontWeight: 600,
|
|
1288
|
+
textTransform: "uppercase"
|
|
1289
|
+
},
|
|
1290
|
+
children: item.type === "property" ? styles.label : "Market News"
|
|
1291
|
+
}
|
|
1292
|
+
)
|
|
1293
|
+
]
|
|
1294
|
+
}
|
|
1295
|
+
)
|
|
1296
|
+
]
|
|
1297
|
+
},
|
|
1298
|
+
key
|
|
1299
|
+
);
|
|
1300
|
+
}) : emptyState ?? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center rounded-2xl border border-dashed border-white/20 px-6 py-10 text-center text-sm text-white/60", children: [
|
|
1301
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Newspaper, { className: "mb-3 h-8 w-8 text-white/40" }),
|
|
1302
|
+
"No property news yet. Updates will land here as soon as we receive new intelligence."
|
|
1303
|
+
] })
|
|
1304
|
+
}
|
|
1305
|
+
),
|
|
1306
|
+
hasItems && totalPages > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center justify-between text-xs text-white/60", children: [
|
|
1307
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1308
|
+
"button",
|
|
1309
|
+
{
|
|
1310
|
+
type: "button",
|
|
1311
|
+
onClick: () => setPage((prev) => Math.max(0, prev - 1)),
|
|
1312
|
+
disabled: page === 0,
|
|
1313
|
+
className: cn(
|
|
1314
|
+
"rounded-full border border-white/15 px-3 py-1 uppercase tracking-[0.2em]",
|
|
1315
|
+
page === 0 ? "opacity-40 cursor-not-allowed" : "hover:border-white/40"
|
|
1316
|
+
),
|
|
1317
|
+
children: "Prev"
|
|
1318
|
+
}
|
|
1319
|
+
),
|
|
1320
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-white/70", children: [
|
|
1321
|
+
"Page ",
|
|
1322
|
+
page + 1,
|
|
1323
|
+
" / ",
|
|
1324
|
+
totalPages
|
|
1325
|
+
] }),
|
|
1326
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1327
|
+
"button",
|
|
1328
|
+
{
|
|
1329
|
+
type: "button",
|
|
1330
|
+
onClick: () => setPage((prev) => Math.min(totalPages - 1, prev + 1)),
|
|
1331
|
+
disabled: page >= totalPages - 1,
|
|
1332
|
+
className: cn(
|
|
1333
|
+
"rounded-full border border-white/15 px-3 py-1 uppercase tracking-[0.2em]",
|
|
1334
|
+
page >= totalPages - 1 ? "opacity-40 cursor-not-allowed" : "hover:border-white/40"
|
|
1335
|
+
),
|
|
1336
|
+
children: "Next"
|
|
1337
|
+
}
|
|
1338
|
+
)
|
|
1339
|
+
] }) : null
|
|
1246
1340
|
]
|
|
1247
1341
|
}
|
|
1248
1342
|
);
|
|
@@ -1317,12 +1411,13 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
1317
1411
|
{
|
|
1318
1412
|
ref,
|
|
1319
1413
|
className: cn(
|
|
1320
|
-
"flex w-full flex-col gap-3
|
|
1414
|
+
"flex w-full flex-col gap-3 border border-white/10 px-4 py-3 text-white shadow-[0_18px_40px_rgba(0,0,0,0.55)] md:flex-row md:items-center md:justify-between md:gap-4",
|
|
1321
1415
|
className
|
|
1322
1416
|
),
|
|
1417
|
+
style: { borderRadius: "16px" },
|
|
1323
1418
|
...props,
|
|
1324
1419
|
children: [
|
|
1325
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative
|
|
1420
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-auto", ref: dropdownRef, children: [
|
|
1326
1421
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1327
1422
|
"button",
|
|
1328
1423
|
{
|
|
@@ -1330,7 +1425,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
1330
1425
|
disabled: !hasAddresses,
|
|
1331
1426
|
onClick: () => setIsDropdownOpen((prev) => !prev),
|
|
1332
1427
|
className: cn(
|
|
1333
|
-
"flex h-[42px] w-
|
|
1428
|
+
"flex h-[42px] w-auto items-center gap-2 rounded-[12px] border border-transparent bg-transparent px-0 text-left text-[15px] font-semibold text-white transition hover:text-white/80 focus-visible:outline-none",
|
|
1334
1429
|
!hasAddresses && "text-white/40"
|
|
1335
1430
|
),
|
|
1336
1431
|
children: [
|
|
@@ -1349,7 +1444,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
1349
1444
|
]
|
|
1350
1445
|
}
|
|
1351
1446
|
),
|
|
1352
|
-
isDropdownOpen && hasAddresses ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-[calc(100%+8px)] z-20 w-full rounded-[12px] border border-
|
|
1447
|
+
isDropdownOpen && hasAddresses ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 top-[calc(100%+8px)] z-20 w-full rounded-[12px] border border-white/10 py-1 shadow-[0_25px_55px_rgba(0,0,0,0.6)] bg-black", children: normalizedAddresses.map((option) => {
|
|
1353
1448
|
const active = option.id === resolvedSelectedId;
|
|
1354
1449
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1355
1450
|
"button",
|
|
@@ -1371,7 +1466,7 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
1371
1466
|
{
|
|
1372
1467
|
variant: "accentOutline",
|
|
1373
1468
|
size: "sm",
|
|
1374
|
-
className: "flex
|
|
1469
|
+
className: "flex items-center justify-center gap-2 rounded-[10px] border-[var(--color-accent,#e6c87e)] bg-transparent px-4 py-2 text-[14px] font-semibold text-[var(--color-accent,#e6c87e)] transition hover:bg-[rgba(230,200,126,0.08)] md:ml-auto",
|
|
1375
1470
|
onClick: onCompareClick,
|
|
1376
1471
|
disabled: !hasAddresses,
|
|
1377
1472
|
children: [
|
|
@@ -1386,152 +1481,263 @@ var PropertyCompareBar = React5__namespace.forwardRef(
|
|
|
1386
1481
|
}
|
|
1387
1482
|
);
|
|
1388
1483
|
PropertyCompareBar.displayName = "PropertyCompareBar";
|
|
1389
|
-
var
|
|
1390
|
-
|
|
1391
|
-
"
|
|
1392
|
-
{
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1484
|
+
var TABS = [
|
|
1485
|
+
{ id: "portfolio", label: "Portfolio" },
|
|
1486
|
+
{ id: "openOrders", label: "Open Orders" },
|
|
1487
|
+
{ id: "tradeHistory", label: "Trade History" },
|
|
1488
|
+
{ id: "orderHistory", label: "Order History" }
|
|
1489
|
+
];
|
|
1490
|
+
var panelStyle = {
|
|
1491
|
+
width: "100%",
|
|
1492
|
+
borderRadius: "16px",
|
|
1493
|
+
backgroundColor: "#111111",
|
|
1494
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
1495
|
+
color: "#ffffff",
|
|
1496
|
+
display: "flex",
|
|
1497
|
+
flexDirection: "column"
|
|
1498
|
+
};
|
|
1499
|
+
var headerStyle = {
|
|
1500
|
+
padding: "1.25rem 1.5rem 0.5rem"
|
|
1501
|
+
};
|
|
1502
|
+
var titleStyle = {
|
|
1503
|
+
margin: 0,
|
|
1504
|
+
fontSize: "1.1rem",
|
|
1505
|
+
fontWeight: 600
|
|
1506
|
+
};
|
|
1507
|
+
var tabsRowStyle = {
|
|
1508
|
+
display: "flex",
|
|
1509
|
+
gap: "0.5rem",
|
|
1510
|
+
padding: "0 1.5rem",
|
|
1511
|
+
borderBottom: "1px solid rgba(255,255,255,0.08)"
|
|
1512
|
+
};
|
|
1513
|
+
var tabButtonBase = {
|
|
1514
|
+
background: "none",
|
|
1515
|
+
border: "none",
|
|
1516
|
+
color: "rgba(255,255,255,0.5)",
|
|
1517
|
+
fontSize: "0.9rem",
|
|
1518
|
+
fontWeight: 400,
|
|
1519
|
+
padding: "0.75rem 1rem",
|
|
1520
|
+
cursor: "pointer",
|
|
1521
|
+
position: "relative",
|
|
1522
|
+
transition: "color 0.2s ease"
|
|
1523
|
+
};
|
|
1524
|
+
var tabContentWrapper = {
|
|
1525
|
+
padding: "1.25rem 1.5rem 1.5rem",
|
|
1526
|
+
display: "flex",
|
|
1527
|
+
flexDirection: "column",
|
|
1528
|
+
gap: "0.75rem",
|
|
1529
|
+
flex: 1
|
|
1530
|
+
};
|
|
1531
|
+
var tableHeaderStyle = {
|
|
1532
|
+
display: "grid",
|
|
1533
|
+
gridTemplateColumns: "1.8fr 0.9fr 0.7fr 0.8fr 0.8fr 1fr",
|
|
1534
|
+
gap: "0.5rem",
|
|
1535
|
+
paddingBottom: "0.75rem",
|
|
1536
|
+
borderBottom: "1px solid rgba(255,255,255,0.1)",
|
|
1537
|
+
minWidth: "700px"
|
|
1538
|
+
};
|
|
1539
|
+
var tableHeaderCell = {
|
|
1540
|
+
fontSize: "0.7rem",
|
|
1541
|
+
fontWeight: 700,
|
|
1542
|
+
color: "#ffffff",
|
|
1543
|
+
textTransform: "uppercase",
|
|
1544
|
+
letterSpacing: "0.3px"
|
|
1545
|
+
};
|
|
1546
|
+
var emptyStateStyle = {
|
|
1547
|
+
flex: 1,
|
|
1548
|
+
display: "flex",
|
|
1549
|
+
alignItems: "center",
|
|
1550
|
+
justifyContent: "center",
|
|
1551
|
+
textAlign: "center",
|
|
1552
|
+
color: "rgba(255,255,255,0.6)",
|
|
1553
|
+
fontSize: "0.95rem",
|
|
1554
|
+
border: "1px dashed rgba(255,255,255,0.12)",
|
|
1555
|
+
borderRadius: "8px",
|
|
1556
|
+
minHeight: "220px"
|
|
1557
|
+
};
|
|
1558
|
+
var rowStyle = {
|
|
1559
|
+
display: "grid",
|
|
1560
|
+
gridTemplateColumns: "1.8fr 0.9fr 0.7fr 0.8fr 0.8fr 1fr",
|
|
1561
|
+
gap: "0.5rem",
|
|
1562
|
+
alignItems: "center",
|
|
1563
|
+
minWidth: "700px",
|
|
1564
|
+
padding: "0.75rem 0",
|
|
1565
|
+
borderBottom: "1px solid rgba(255,255,255,0.08)"
|
|
1566
|
+
};
|
|
1567
|
+
var formatCurrency = (value) => {
|
|
1568
|
+
if (value == null || Number.isNaN(value)) return "\u2014";
|
|
1569
|
+
return `$${value.toLocaleString(void 0, {
|
|
1570
|
+
minimumFractionDigits: 2,
|
|
1571
|
+
maximumFractionDigits: 2
|
|
1572
|
+
})}`;
|
|
1573
|
+
};
|
|
1574
|
+
var formatPercent = (value, fractionDigits = 2) => {
|
|
1575
|
+
if (value == null || Number.isNaN(value)) return "\u2014";
|
|
1576
|
+
return `${value.toFixed(fractionDigits)}%`;
|
|
1577
|
+
};
|
|
1421
1578
|
var YourOrders = React5__namespace.forwardRef(
|
|
1422
|
-
({
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
)
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
"button",
|
|
1475
|
-
{
|
|
1476
|
-
type: "button",
|
|
1477
|
-
onClick: canEditPrice ? () => onEditPrice?.(order) : void 0,
|
|
1478
|
-
className: cn(
|
|
1479
|
-
"ml-1 inline-flex items-center justify-center text-white/60 transition-colors",
|
|
1480
|
-
canEditPrice ? "cursor-pointer hover:text-[#C9A227] active:translate-y-px" : "cursor-default"
|
|
1481
|
-
),
|
|
1482
|
-
"aria-label": "Edit price",
|
|
1483
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(EditIcon, { className: "h-[14px] w-[14px]" })
|
|
1484
|
-
}
|
|
1485
|
-
)
|
|
1486
|
-
] }),
|
|
1487
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-2 font-medium", children: [
|
|
1488
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: order.amount.toLocaleString() }),
|
|
1489
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1490
|
-
"button",
|
|
1579
|
+
({ className, title = "Portfolio Holdings (Demo)", orders, ...props }, ref) => {
|
|
1580
|
+
const [activeTab, setActiveTab] = React5__namespace.useState("portfolio");
|
|
1581
|
+
const hasOrders = Array.isArray(orders) && orders.length > 0;
|
|
1582
|
+
const renderPortfolio = () => {
|
|
1583
|
+
if (!hasOrders) {
|
|
1584
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStateStyle, children: "No holdings yet. Start trading to build your portfolio." });
|
|
1585
|
+
}
|
|
1586
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: tableHeaderStyle, children: [
|
|
1588
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Property" }),
|
|
1589
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Value" }),
|
|
1590
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Holding" }),
|
|
1591
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "% of Property" }),
|
|
1592
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "Avg Price" }),
|
|
1593
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tableHeaderCell, children: "P&L" })
|
|
1594
|
+
] }),
|
|
1595
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.65rem" }, children: orders.map((order) => {
|
|
1596
|
+
const propertyName = order.asset;
|
|
1597
|
+
const holding = order.holdingLabel ?? `${order.amount.toLocaleString(void 0, {
|
|
1598
|
+
minimumFractionDigits: 0,
|
|
1599
|
+
maximumFractionDigits: 2
|
|
1600
|
+
})} ${propertyName}`;
|
|
1601
|
+
const value = order.value ?? order.total;
|
|
1602
|
+
const portfolioShare = order.portfolioSharePercent != null ? `${order.portfolioSharePercent.toFixed(1)}% of portfolio` : void 0;
|
|
1603
|
+
const propertyPercent = order.propertyPercent;
|
|
1604
|
+
const avgPrice = order.avgEntryPrice ?? order.price;
|
|
1605
|
+
const pnlValue = order.pnlValue;
|
|
1606
|
+
const pnlPercent = order.pnlPercent;
|
|
1607
|
+
const pnlPositive = pnlValue != null ? pnlValue >= 0 : (pnlPercent ?? 0) >= 0;
|
|
1608
|
+
const currentPrice = order.currentPrice ?? order.price;
|
|
1609
|
+
const priceChangePercent = order.priceChangePercent ?? order.pnlPercent;
|
|
1610
|
+
const priceChangePositive = order.priceChangePositive ?? (priceChangePercent != null ? priceChangePercent >= 0 : void 0);
|
|
1611
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rowStyle, children: [
|
|
1612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "1rem", alignItems: "center" }, children: [
|
|
1613
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.15rem" }, children: [
|
|
1614
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", fontWeight: 500 }, children: propertyName }),
|
|
1615
|
+
portfolioShare ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.72rem", color: "rgba(255,255,255,0.5)" }, children: portfolioShare }) : null
|
|
1616
|
+
] }),
|
|
1617
|
+
currentPrice != null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1618
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1619
|
+
"div",
|
|
1620
|
+
{
|
|
1621
|
+
style: {
|
|
1622
|
+
fontSize: "0.9rem",
|
|
1623
|
+
color: "var(--color-text, #ffffff)",
|
|
1624
|
+
display: "flex",
|
|
1625
|
+
alignItems: "center",
|
|
1626
|
+
gap: "0.25rem"
|
|
1627
|
+
},
|
|
1628
|
+
children: [
|
|
1629
|
+
priceChangePositive != null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1630
|
+
"span",
|
|
1491
1631
|
{
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
),
|
|
1498
|
-
"aria-label": "Edit amount",
|
|
1499
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(EditIcon, { className: "h-[14px] w-[14px]" })
|
|
1632
|
+
style: {
|
|
1633
|
+
color: priceChangePositive ? "#0ecb81" : "#f6465d",
|
|
1634
|
+
fontSize: "0.7em"
|
|
1635
|
+
},
|
|
1636
|
+
children: priceChangePositive ? "\u25B2" : "\u25BC"
|
|
1500
1637
|
}
|
|
1501
|
-
)
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
"
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1638
|
+
) : null,
|
|
1639
|
+
formatCurrency(currentPrice)
|
|
1640
|
+
]
|
|
1641
|
+
}
|
|
1642
|
+
),
|
|
1643
|
+
priceChangePercent != null ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1644
|
+
"div",
|
|
1645
|
+
{
|
|
1646
|
+
style: {
|
|
1647
|
+
fontSize: "0.7rem",
|
|
1648
|
+
color: priceChangePositive ? "#0ecb81" : "#f6465d"
|
|
1649
|
+
},
|
|
1650
|
+
children: [
|
|
1651
|
+
"(",
|
|
1652
|
+
priceChangePositive ? "+" : "",
|
|
1653
|
+
priceChangePercent.toFixed(2),
|
|
1654
|
+
"%)"
|
|
1655
|
+
]
|
|
1656
|
+
}
|
|
1657
|
+
) : null
|
|
1658
|
+
] }) : null
|
|
1659
|
+
] }),
|
|
1660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", fontWeight: 500, color: "#D4AF37" }, children: formatCurrency(value) }),
|
|
1661
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", color: "rgba(255,255,255,0.92)" }, children: holding }),
|
|
1662
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", color: "rgba(255,255,255,0.8)" }, children: formatPercent(propertyPercent, 3) }),
|
|
1663
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.9rem", color: "rgba(255,255,255,0.9)" }, children: formatCurrency(avgPrice) }),
|
|
1664
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1665
|
+
"div",
|
|
1666
|
+
{
|
|
1667
|
+
style: {
|
|
1668
|
+
fontSize: "0.9rem",
|
|
1669
|
+
fontWeight: 500,
|
|
1670
|
+
color: pnlPositive ? "#0ecb81" : "#f6465d"
|
|
1527
1671
|
},
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1672
|
+
children: [
|
|
1673
|
+
pnlValue != null ? `${pnlPositive ? "+" : "-"}${formatCurrency(Math.abs(pnlValue))}` : formatCurrency(pnlValue),
|
|
1674
|
+
pnlPercent != null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: "0.35rem", fontSize: "0.75rem", color: "rgba(255,255,255,0.6)" }, children: [
|
|
1675
|
+
"(",
|
|
1676
|
+
pnlPositive ? "+" : "",
|
|
1677
|
+
pnlPercent.toFixed(1),
|
|
1678
|
+
"%)"
|
|
1679
|
+
] }) : null
|
|
1680
|
+
]
|
|
1681
|
+
}
|
|
1682
|
+
)
|
|
1683
|
+
] }, order.id);
|
|
1684
|
+
}) })
|
|
1685
|
+
] });
|
|
1686
|
+
};
|
|
1687
|
+
const renderOtherTab = (label) => /* @__PURE__ */ jsxRuntime.jsx("div", { style: emptyStateStyle, children: `No ${label.toLowerCase()} data available.` });
|
|
1688
|
+
let tabContent = null;
|
|
1689
|
+
switch (activeTab) {
|
|
1690
|
+
case "portfolio":
|
|
1691
|
+
tabContent = renderPortfolio();
|
|
1692
|
+
break;
|
|
1693
|
+
case "openOrders":
|
|
1694
|
+
tabContent = renderOtherTab("Open Orders");
|
|
1695
|
+
break;
|
|
1696
|
+
case "tradeHistory":
|
|
1697
|
+
tabContent = renderOtherTab("Trade History");
|
|
1698
|
+
break;
|
|
1699
|
+
case "orderHistory":
|
|
1700
|
+
tabContent = renderOtherTab("Order History");
|
|
1701
|
+
break;
|
|
1702
|
+
default:
|
|
1703
|
+
tabContent = null;
|
|
1704
|
+
}
|
|
1705
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, style: panelStyle, className, ...props, children: [
|
|
1706
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle, children: /* @__PURE__ */ jsxRuntime.jsx("h3", { style: titleStyle, children: title }) }),
|
|
1707
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tabsRowStyle, children: TABS.map((tab) => {
|
|
1708
|
+
const isActive = activeTab === tab.id;
|
|
1709
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1710
|
+
"button",
|
|
1711
|
+
{
|
|
1712
|
+
type: "button",
|
|
1713
|
+
onClick: () => setActiveTab(tab.id),
|
|
1714
|
+
style: {
|
|
1715
|
+
...tabButtonBase,
|
|
1716
|
+
color: isActive ? "#ffffff" : "rgba(255,255,255,0.55)",
|
|
1717
|
+
fontWeight: isActive ? 600 : 400
|
|
1718
|
+
},
|
|
1719
|
+
children: [
|
|
1720
|
+
tab.label,
|
|
1721
|
+
isActive ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1722
|
+
"div",
|
|
1723
|
+
{
|
|
1724
|
+
style: {
|
|
1725
|
+
position: "absolute",
|
|
1726
|
+
bottom: "-1px",
|
|
1727
|
+
left: 0,
|
|
1728
|
+
right: 0,
|
|
1729
|
+
height: "2px",
|
|
1730
|
+
background: "#f0b90b"
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
) : null
|
|
1734
|
+
]
|
|
1735
|
+
},
|
|
1736
|
+
tab.id
|
|
1737
|
+
);
|
|
1738
|
+
}) }),
|
|
1739
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: tabContentWrapper, children: tabContent })
|
|
1740
|
+
] });
|
|
1535
1741
|
}
|
|
1536
1742
|
);
|
|
1537
1743
|
YourOrders.displayName = "YourOrders";
|
|
@@ -1741,7 +1947,10 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
1741
1947
|
...props
|
|
1742
1948
|
}, ref) => {
|
|
1743
1949
|
const isPositive = changePercent == null ? void 0 : changePercent >= 0;
|
|
1744
|
-
const
|
|
1950
|
+
const accentColor = "#e6c87e";
|
|
1951
|
+
const tradeHoverColor = "#f5dd9a";
|
|
1952
|
+
const [isTradeInteracting, setIsTradeInteracting] = React5__namespace.useState(false);
|
|
1953
|
+
const [isOfferInteracting, setIsOfferInteracting] = React5__namespace.useState(false);
|
|
1745
1954
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1746
1955
|
"div",
|
|
1747
1956
|
{
|
|
@@ -1827,20 +2036,30 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
1827
2036
|
propertyTypeLabel == null ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { children: propertyTypeLabel })
|
|
1828
2037
|
] })
|
|
1829
2038
|
] }),
|
|
1830
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-
|
|
2039
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3 max-[768px]:w-full max-[768px]:justify-between max-[768px]:gap-2 max-[480px]:gap-2", children: [
|
|
1831
2040
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1832
2041
|
"button",
|
|
1833
2042
|
{
|
|
1834
2043
|
type: "button",
|
|
1835
2044
|
onClick: onTrade,
|
|
1836
|
-
className: "
|
|
1837
|
-
style: {
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
2045
|
+
className: "flex items-center justify-center rounded border font-semibold transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] text-[0.95rem] max-[480px]:text-[0.9rem]",
|
|
2046
|
+
style: {
|
|
2047
|
+
backgroundColor: isTradeInteracting ? tradeHoverColor : accentColor,
|
|
2048
|
+
color: "black",
|
|
2049
|
+
width: "88.06px",
|
|
2050
|
+
height: "43px",
|
|
2051
|
+
minWidth: "88.06px",
|
|
2052
|
+
borderColor: isTradeInteracting ? accentColor : "transparent",
|
|
2053
|
+
boxShadow: isTradeInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none"
|
|
1843
2054
|
},
|
|
2055
|
+
onMouseEnter: () => setIsTradeInteracting(true),
|
|
2056
|
+
onMouseLeave: () => setIsTradeInteracting(false),
|
|
2057
|
+
onMouseDown: () => setIsTradeInteracting(true),
|
|
2058
|
+
onMouseUp: () => setIsTradeInteracting(false),
|
|
2059
|
+
onFocus: () => setIsTradeInteracting(true),
|
|
2060
|
+
onBlur: () => setIsTradeInteracting(false),
|
|
2061
|
+
onTouchStart: () => setIsTradeInteracting(true),
|
|
2062
|
+
onTouchEnd: () => setIsTradeInteracting(false),
|
|
1844
2063
|
children: "Trade"
|
|
1845
2064
|
}
|
|
1846
2065
|
),
|
|
@@ -1849,18 +2068,24 @@ var PropertyHeroHeader = React5__namespace.forwardRef(
|
|
|
1849
2068
|
{
|
|
1850
2069
|
type: "button",
|
|
1851
2070
|
onClick: onMakeOffer,
|
|
1852
|
-
className: "
|
|
2071
|
+
className: "flex items-center justify-center rounded border font-semibold transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] text-[0.95rem] max-[480px]:text-[0.9rem]",
|
|
1853
2072
|
style: {
|
|
1854
|
-
backgroundColor: "transparent",
|
|
1855
|
-
borderColor:
|
|
1856
|
-
color: "
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
onMouseLeave: (e) => {
|
|
1862
|
-
e.currentTarget.style.backgroundColor = "transparent";
|
|
2073
|
+
backgroundColor: isOfferInteracting ? accentColor : "transparent",
|
|
2074
|
+
borderColor: accentColor,
|
|
2075
|
+
color: isOfferInteracting ? "black" : accentColor,
|
|
2076
|
+
width: "127.14px",
|
|
2077
|
+
height: "43px",
|
|
2078
|
+
minWidth: "127.14px",
|
|
2079
|
+
boxShadow: isOfferInteracting ? `0 0 0 2px rgba(0,0,0,0.4), 0 0 0 4px ${accentColor}` : "none"
|
|
1863
2080
|
},
|
|
2081
|
+
onMouseEnter: () => setIsOfferInteracting(true),
|
|
2082
|
+
onMouseLeave: () => setIsOfferInteracting(false),
|
|
2083
|
+
onMouseDown: () => setIsOfferInteracting(true),
|
|
2084
|
+
onMouseUp: () => setIsOfferInteracting(false),
|
|
2085
|
+
onFocus: () => setIsOfferInteracting(true),
|
|
2086
|
+
onBlur: () => setIsOfferInteracting(false),
|
|
2087
|
+
onTouchStart: () => setIsOfferInteracting(true),
|
|
2088
|
+
onTouchEnd: () => setIsOfferInteracting(false),
|
|
1864
2089
|
children: "Make Offer"
|
|
1865
2090
|
}
|
|
1866
2091
|
)
|