@loafmarkets/ui 0.1.42 → 0.1.43
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 +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +794 -354
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +677 -240
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import
|
|
1
|
+
import * as React9 from 'react';
|
|
2
|
+
import React9__default, { createContext, useState, useEffect, useMemo, useCallback, useRef, useContext } from 'react';
|
|
3
3
|
import { Slot } from '@radix-ui/react-slot';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
@@ -50,7 +50,7 @@ var buttonVariants = cva(
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
);
|
|
53
|
-
var Button =
|
|
53
|
+
var Button = React9.forwardRef(
|
|
54
54
|
({ className, variant, size, radius, asChild = false, ...props }, ref) => {
|
|
55
55
|
const Comp = asChild ? Slot : "button";
|
|
56
56
|
const coercedRadius = radius ?? (variant === "onboarding" || variant === "onboardingOutline" ? "square" : void 0);
|
|
@@ -89,11 +89,11 @@ var badgeVariants = cva(
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
);
|
|
92
|
-
var Badge =
|
|
92
|
+
var Badge = React9.forwardRef(
|
|
93
93
|
({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
|
|
94
94
|
);
|
|
95
95
|
Badge.displayName = "Badge";
|
|
96
|
-
var Card =
|
|
96
|
+
var Card = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
97
97
|
"div",
|
|
98
98
|
{
|
|
99
99
|
ref,
|
|
@@ -105,11 +105,11 @@ var Card = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ j
|
|
|
105
105
|
}
|
|
106
106
|
));
|
|
107
107
|
Card.displayName = "Card";
|
|
108
|
-
var CardHeader =
|
|
108
|
+
var CardHeader = React9.forwardRef(
|
|
109
109
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
|
|
110
110
|
);
|
|
111
111
|
CardHeader.displayName = "CardHeader";
|
|
112
|
-
var CardTitle =
|
|
112
|
+
var CardTitle = React9.forwardRef(
|
|
113
113
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
114
114
|
"h3",
|
|
115
115
|
{
|
|
@@ -120,15 +120,15 @@ var CardTitle = React5.forwardRef(
|
|
|
120
120
|
)
|
|
121
121
|
);
|
|
122
122
|
CardTitle.displayName = "CardTitle";
|
|
123
|
-
var CardDescription =
|
|
123
|
+
var CardDescription = React9.forwardRef(
|
|
124
124
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
|
|
125
125
|
);
|
|
126
126
|
CardDescription.displayName = "CardDescription";
|
|
127
|
-
var CardContent =
|
|
127
|
+
var CardContent = React9.forwardRef(
|
|
128
128
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
|
|
129
129
|
);
|
|
130
130
|
CardContent.displayName = "CardContent";
|
|
131
|
-
var CardFooter =
|
|
131
|
+
var CardFooter = React9.forwardRef(
|
|
132
132
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
|
|
133
133
|
);
|
|
134
134
|
CardFooter.displayName = "CardFooter";
|
|
@@ -146,7 +146,7 @@ var defaultFormatSignedCurrency = (value) => {
|
|
|
146
146
|
const sign = value >= 0 ? "+" : "-";
|
|
147
147
|
return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
|
|
148
148
|
};
|
|
149
|
-
var PortfolioSummary =
|
|
149
|
+
var PortfolioSummary = React9.forwardRef(
|
|
150
150
|
({
|
|
151
151
|
availableCash,
|
|
152
152
|
portfolioValue,
|
|
@@ -296,23 +296,23 @@ function HousePositionSlider({
|
|
|
296
296
|
className,
|
|
297
297
|
...props
|
|
298
298
|
}) {
|
|
299
|
-
const [orderMode, setOrderMode] =
|
|
300
|
-
const [buyTrackingMode, setBuyTrackingMode] =
|
|
301
|
-
const [deltaDollars, setDeltaDollars] =
|
|
302
|
-
const [deltaTokensBuy, setDeltaTokensBuy] =
|
|
303
|
-
const [deltaTokensSell, setDeltaTokensSell] =
|
|
304
|
-
const [_isDragging, setIsDragging] =
|
|
305
|
-
const [visualTargetPct, setVisualTargetPct] =
|
|
306
|
-
const [orderType, setOrderType] =
|
|
307
|
-
const [limitPrice, setLimitPrice] =
|
|
308
|
-
const [limitPriceInput, setLimitPriceInput] =
|
|
309
|
-
const [limitPriceDirty, setLimitPriceDirty] =
|
|
310
|
-
const [ownershipInput, setOwnershipInput] =
|
|
311
|
-
const [tokenAmountInput, setTokenAmountInput] =
|
|
312
|
-
const houseRef =
|
|
299
|
+
const [orderMode, setOrderMode] = React9.useState("none");
|
|
300
|
+
const [buyTrackingMode, setBuyTrackingMode] = React9.useState("dollars");
|
|
301
|
+
const [deltaDollars, setDeltaDollars] = React9.useState(0);
|
|
302
|
+
const [deltaTokensBuy, setDeltaTokensBuy] = React9.useState(0);
|
|
303
|
+
const [deltaTokensSell, setDeltaTokensSell] = React9.useState(0);
|
|
304
|
+
const [_isDragging, setIsDragging] = React9.useState(false);
|
|
305
|
+
const [visualTargetPct, setVisualTargetPct] = React9.useState(null);
|
|
306
|
+
const [orderType, setOrderType] = React9.useState(defaultOrderType);
|
|
307
|
+
const [limitPrice, setLimitPrice] = React9.useState(currentPrice);
|
|
308
|
+
const [limitPriceInput, setLimitPriceInput] = React9.useState(currentPrice.toFixed(2));
|
|
309
|
+
const [limitPriceDirty, setLimitPriceDirty] = React9.useState(false);
|
|
310
|
+
const [ownershipInput, setOwnershipInput] = React9.useState("");
|
|
311
|
+
const [tokenAmountInput, setTokenAmountInput] = React9.useState("");
|
|
312
|
+
const houseRef = React9.useRef(null);
|
|
313
313
|
const asks = orderbook?.asks ?? [];
|
|
314
314
|
const bids = orderbook?.bids ?? [];
|
|
315
|
-
|
|
315
|
+
React9.useEffect(() => {
|
|
316
316
|
if (orderType !== "limit") return;
|
|
317
317
|
if (limitPriceDirty) return;
|
|
318
318
|
setLimitPrice(currentPrice);
|
|
@@ -387,7 +387,7 @@ function HousePositionSlider({
|
|
|
387
387
|
const impliedDisplayTargetOwnership = clamp(targetOwnership + ownershipShift, 0, 100);
|
|
388
388
|
const displayTargetOwnership = visualTargetPct ?? impliedDisplayTargetOwnership;
|
|
389
389
|
const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
|
|
390
|
-
const resetOrder =
|
|
390
|
+
const resetOrder = React9.useCallback(() => {
|
|
391
391
|
setOrderMode("none");
|
|
392
392
|
setBuyTrackingMode("dollars");
|
|
393
393
|
setDeltaDollars(0);
|
|
@@ -395,7 +395,7 @@ function HousePositionSlider({
|
|
|
395
395
|
setDeltaTokensSell(0);
|
|
396
396
|
setVisualTargetPct(null);
|
|
397
397
|
}, []);
|
|
398
|
-
const updateOrderFromTargetValue =
|
|
398
|
+
const updateOrderFromTargetValue = React9.useCallback(
|
|
399
399
|
(newTargetValue) => {
|
|
400
400
|
const newDeltaValue = newTargetValue - holdingsValue;
|
|
401
401
|
if (newDeltaValue > 0) {
|
|
@@ -419,7 +419,7 @@ function HousePositionSlider({
|
|
|
419
419
|
},
|
|
420
420
|
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, resetOrder, tokensHeld]
|
|
421
421
|
);
|
|
422
|
-
const updateOrderFromOwnership =
|
|
422
|
+
const updateOrderFromOwnership = React9.useCallback(
|
|
423
423
|
(newOwnershipPercent) => {
|
|
424
424
|
const nextOwnership = clamp(newOwnershipPercent, 0, 100);
|
|
425
425
|
const newTargetTokens = nextOwnership / 100 * totalTokens;
|
|
@@ -428,7 +428,7 @@ function HousePositionSlider({
|
|
|
428
428
|
},
|
|
429
429
|
[effectivePrice, totalTokens, updateOrderFromTargetValue]
|
|
430
430
|
);
|
|
431
|
-
const updateOrderFromTokenAmount =
|
|
431
|
+
const updateOrderFromTokenAmount = React9.useCallback(
|
|
432
432
|
(tokenAmountSigned) => {
|
|
433
433
|
if (tokenAmountSigned > 0) {
|
|
434
434
|
const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
|
|
@@ -451,7 +451,7 @@ function HousePositionSlider({
|
|
|
451
451
|
},
|
|
452
452
|
[effectiveAvailableCash, effectivePrice, effectiveTokensHeld, resetOrder]
|
|
453
453
|
);
|
|
454
|
-
const updateOrderFromSlider =
|
|
454
|
+
const updateOrderFromSlider = React9.useCallback(
|
|
455
455
|
(pct) => {
|
|
456
456
|
const normalized = (pct - 50) / 50;
|
|
457
457
|
const magnitude = Math.min(Math.abs(normalized), 1);
|
|
@@ -495,7 +495,7 @@ function HousePositionSlider({
|
|
|
495
495
|
},
|
|
496
496
|
[effectiveAvailableCash, effectiveTokensHeld, resetOrder]
|
|
497
497
|
);
|
|
498
|
-
const handleDragAtClientY =
|
|
498
|
+
const handleDragAtClientY = React9.useCallback(
|
|
499
499
|
(clientY) => {
|
|
500
500
|
if (!houseRef.current) return;
|
|
501
501
|
const rect = houseRef.current.getBoundingClientRect();
|
|
@@ -1011,18 +1011,18 @@ function HousePositionSliderMobile({
|
|
|
1011
1011
|
className,
|
|
1012
1012
|
...props
|
|
1013
1013
|
}) {
|
|
1014
|
-
const [orderMode, setOrderMode] =
|
|
1015
|
-
const [deltaDollars, setDeltaDollars] =
|
|
1016
|
-
const [deltaTokensSell, setDeltaTokensSell] =
|
|
1017
|
-
const [deltaTokensBuy, setDeltaTokensBuy] =
|
|
1018
|
-
const [buyTrackingMode, setBuyTrackingMode] =
|
|
1019
|
-
const [orderType, setOrderType] =
|
|
1020
|
-
const [limitPrice, setLimitPrice] =
|
|
1021
|
-
const [limitPriceInput, setLimitPriceInput] =
|
|
1022
|
-
const [limitPriceDirty, setLimitPriceDirty] =
|
|
1023
|
-
const [tokenAmountInput, setTokenAmountInput] =
|
|
1024
|
-
const houseRef =
|
|
1025
|
-
|
|
1014
|
+
const [orderMode, setOrderMode] = React9.useState("none");
|
|
1015
|
+
const [deltaDollars, setDeltaDollars] = React9.useState(0);
|
|
1016
|
+
const [deltaTokensSell, setDeltaTokensSell] = React9.useState(0);
|
|
1017
|
+
const [deltaTokensBuy, setDeltaTokensBuy] = React9.useState(0);
|
|
1018
|
+
const [buyTrackingMode, setBuyTrackingMode] = React9.useState("dollars");
|
|
1019
|
+
const [orderType, setOrderType] = React9.useState(defaultOrderType);
|
|
1020
|
+
const [limitPrice, setLimitPrice] = React9.useState(currentPrice);
|
|
1021
|
+
const [limitPriceInput, setLimitPriceInput] = React9.useState(currentPrice.toFixed(2));
|
|
1022
|
+
const [limitPriceDirty, setLimitPriceDirty] = React9.useState(false);
|
|
1023
|
+
const [tokenAmountInput, setTokenAmountInput] = React9.useState("");
|
|
1024
|
+
const houseRef = React9.useRef(null);
|
|
1025
|
+
React9.useEffect(() => {
|
|
1026
1026
|
if (orderType !== "limit") return;
|
|
1027
1027
|
if (limitPriceDirty) return;
|
|
1028
1028
|
setLimitPrice(currentPrice);
|
|
@@ -1064,7 +1064,7 @@ function HousePositionSliderMobile({
|
|
|
1064
1064
|
const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
|
|
1065
1065
|
const targetOwnership = totalTokens > 0 ? targetTokens / totalTokens * 100 : 0;
|
|
1066
1066
|
const estFeeTokens = effectivePrice > 0 ? Math.abs(deltaValue) * 5e-3 / effectivePrice : 0;
|
|
1067
|
-
const updateOrderFromTargetValue =
|
|
1067
|
+
const updateOrderFromTargetValue = React9.useCallback(
|
|
1068
1068
|
(newTargetValue) => {
|
|
1069
1069
|
const newDeltaValue = newTargetValue - holdingsValue;
|
|
1070
1070
|
if (newDeltaValue > 0.01) {
|
|
@@ -1092,7 +1092,7 @@ function HousePositionSliderMobile({
|
|
|
1092
1092
|
},
|
|
1093
1093
|
[holdingsValue, availableCash, effectivePrice, tokensHeld]
|
|
1094
1094
|
);
|
|
1095
|
-
const updateOrderFromTokenAmount =
|
|
1095
|
+
const updateOrderFromTokenAmount = React9.useCallback(
|
|
1096
1096
|
(tokenAmount) => {
|
|
1097
1097
|
if (tokenAmount > 0) {
|
|
1098
1098
|
const maxTokens = effectivePrice > 0 ? availableCash / effectivePrice : 0;
|
|
@@ -1119,14 +1119,14 @@ function HousePositionSliderMobile({
|
|
|
1119
1119
|
},
|
|
1120
1120
|
[effectivePrice, availableCash, tokensHeld]
|
|
1121
1121
|
);
|
|
1122
|
-
const handleMarkerClick =
|
|
1122
|
+
const handleMarkerClick = React9.useCallback(
|
|
1123
1123
|
(pct) => {
|
|
1124
1124
|
const newTargetValue = pct / 100 * totalCapacity;
|
|
1125
1125
|
updateOrderFromTargetValue(newTargetValue);
|
|
1126
1126
|
},
|
|
1127
1127
|
[totalCapacity, updateOrderFromTargetValue]
|
|
1128
1128
|
);
|
|
1129
|
-
const onMouseDown =
|
|
1129
|
+
const onMouseDown = React9.useCallback(
|
|
1130
1130
|
(e) => {
|
|
1131
1131
|
e.preventDefault();
|
|
1132
1132
|
const move = (ev) => {
|
|
@@ -1146,7 +1146,7 @@ function HousePositionSliderMobile({
|
|
|
1146
1146
|
},
|
|
1147
1147
|
[totalCapacity, updateOrderFromTargetValue]
|
|
1148
1148
|
);
|
|
1149
|
-
const onTouchStart =
|
|
1149
|
+
const onTouchStart = React9.useCallback(
|
|
1150
1150
|
(e) => {
|
|
1151
1151
|
e.preventDefault();
|
|
1152
1152
|
e.stopPropagation();
|
|
@@ -1704,7 +1704,7 @@ var LiquidityText = styled24.span`
|
|
|
1704
1704
|
letter-spacing: 0.1px;
|
|
1705
1705
|
}
|
|
1706
1706
|
`;
|
|
1707
|
-
var LoafLiquidityBadge =
|
|
1707
|
+
var LoafLiquidityBadge = React9.forwardRef(
|
|
1708
1708
|
({ className, isGlowing, onClick, children, ...props }, ref) => {
|
|
1709
1709
|
return /* @__PURE__ */ jsxs(
|
|
1710
1710
|
LogoContainer,
|
|
@@ -1732,9 +1732,34 @@ var LoafLiquidityBadge = React5.forwardRef(
|
|
|
1732
1732
|
}
|
|
1733
1733
|
);
|
|
1734
1734
|
LoafLiquidityBadge.displayName = "LoafLiquidityBadge";
|
|
1735
|
+
var toSize = (v, fallback) => v == null ? fallback : typeof v === "number" ? `${v}px` : v;
|
|
1736
|
+
var Skeleton = React9.forwardRef(
|
|
1737
|
+
({ width, height, radius, className, style, ...props }, ref) => {
|
|
1738
|
+
return /* @__PURE__ */ jsx(
|
|
1739
|
+
"div",
|
|
1740
|
+
{
|
|
1741
|
+
ref,
|
|
1742
|
+
"aria-busy": "true",
|
|
1743
|
+
"aria-live": "polite",
|
|
1744
|
+
className: cn(
|
|
1745
|
+
"inline-block align-middle bg-white/10 animate-pulse",
|
|
1746
|
+
className
|
|
1747
|
+
),
|
|
1748
|
+
style: {
|
|
1749
|
+
width: toSize(width, "100%"),
|
|
1750
|
+
height: toSize(height, "1em"),
|
|
1751
|
+
borderRadius: toSize(radius, "6px"),
|
|
1752
|
+
...style
|
|
1753
|
+
},
|
|
1754
|
+
...props
|
|
1755
|
+
}
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
);
|
|
1759
|
+
Skeleton.displayName = "Skeleton";
|
|
1735
1760
|
function useViewportCompact(breakpoint) {
|
|
1736
|
-
const [isCompact, setIsCompact] =
|
|
1737
|
-
|
|
1761
|
+
const [isCompact, setIsCompact] = React9.useState(false);
|
|
1762
|
+
React9.useEffect(() => {
|
|
1738
1763
|
if (typeof window === "undefined") return;
|
|
1739
1764
|
const check = () => setIsCompact(window.innerWidth <= breakpoint);
|
|
1740
1765
|
check();
|
|
@@ -1744,16 +1769,119 @@ function useViewportCompact(breakpoint) {
|
|
|
1744
1769
|
return isCompact;
|
|
1745
1770
|
}
|
|
1746
1771
|
var formatNumber = (value, precision) => value.toFixed(precision);
|
|
1772
|
+
var FLASH_DURATION_MS = 450;
|
|
1773
|
+
var FLASH_UP_COLOR = "rgba(14, 203, 129, 0.35)";
|
|
1774
|
+
var FLASH_DOWN_COLOR = "rgba(246, 70, 93, 0.35)";
|
|
1775
|
+
function getTradeKey(trade, fallbackIndex) {
|
|
1776
|
+
if (trade.tradeId != null) return `id-${trade.tradeId}`;
|
|
1777
|
+
if (trade.time != null) return `t-${trade.time}-${trade.type}-${trade.price}-${trade.amount}`;
|
|
1778
|
+
return `idx-${fallbackIndex}-${trade.type}-${trade.price}-${trade.amount}`;
|
|
1779
|
+
}
|
|
1780
|
+
function useAmountChangeFlash(ref, amount) {
|
|
1781
|
+
const prevAmountRef = React9.useRef(amount);
|
|
1782
|
+
React9.useEffect(() => {
|
|
1783
|
+
const prev = prevAmountRef.current;
|
|
1784
|
+
const node = ref.current;
|
|
1785
|
+
if (prev !== amount && node && typeof node.animate === "function") {
|
|
1786
|
+
const color = amount > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1787
|
+
node.animate(
|
|
1788
|
+
[{ backgroundColor: color }, { backgroundColor: "transparent" }],
|
|
1789
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
prevAmountRef.current = amount;
|
|
1793
|
+
}, [amount, ref]);
|
|
1794
|
+
}
|
|
1795
|
+
function useMidPriceFlash(ref, midPrice, restBgColor) {
|
|
1796
|
+
const prevMidRef = React9.useRef(midPrice);
|
|
1797
|
+
React9.useEffect(() => {
|
|
1798
|
+
const prev = prevMidRef.current;
|
|
1799
|
+
const node = ref.current;
|
|
1800
|
+
if (prev !== midPrice && prev > 0 && midPrice > 0 && node && typeof node.animate === "function") {
|
|
1801
|
+
const color = midPrice > prev ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1802
|
+
node.animate(
|
|
1803
|
+
[{ backgroundColor: color }, { backgroundColor: restBgColor }],
|
|
1804
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
prevMidRef.current = midPrice;
|
|
1808
|
+
}, [midPrice, ref, restBgColor]);
|
|
1809
|
+
}
|
|
1810
|
+
function TradeRow({
|
|
1811
|
+
trade,
|
|
1812
|
+
tradeKey,
|
|
1813
|
+
precision,
|
|
1814
|
+
amountPrecision,
|
|
1815
|
+
seenTradeKeysRef,
|
|
1816
|
+
compact
|
|
1817
|
+
}) {
|
|
1818
|
+
const rowRef = React9.useRef(null);
|
|
1819
|
+
const { type } = trade;
|
|
1820
|
+
React9.useEffect(() => {
|
|
1821
|
+
if (seenTradeKeysRef.current.has(tradeKey)) return;
|
|
1822
|
+
seenTradeKeysRef.current.add(tradeKey);
|
|
1823
|
+
const node = rowRef.current;
|
|
1824
|
+
if (!node || typeof node.animate !== "function") return;
|
|
1825
|
+
const color = type === "buy" ? FLASH_UP_COLOR : FLASH_DOWN_COLOR;
|
|
1826
|
+
node.animate(
|
|
1827
|
+
[{ backgroundColor: color }, { backgroundColor: "transparent" }],
|
|
1828
|
+
{ duration: FLASH_DURATION_MS, easing: "ease-out" }
|
|
1829
|
+
);
|
|
1830
|
+
}, [tradeKey, seenTradeKeysRef, type]);
|
|
1831
|
+
if (compact) {
|
|
1832
|
+
return /* @__PURE__ */ jsxs(
|
|
1833
|
+
"div",
|
|
1834
|
+
{
|
|
1835
|
+
ref: rowRef,
|
|
1836
|
+
className: "grid",
|
|
1837
|
+
style: { gridTemplateColumns: "1.2fr 0.8fr", padding: "0.2rem 0", fontSize: "0.8rem" },
|
|
1838
|
+
children: [
|
|
1839
|
+
/* @__PURE__ */ jsxs("div", { style: { color: trade.type === "buy" ? "#0ecb81" : "#f6465d", fontWeight: 500 }, children: [
|
|
1840
|
+
"$",
|
|
1841
|
+
formatNumber(trade.price, precision)
|
|
1842
|
+
] }),
|
|
1843
|
+
/* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
|
|
1844
|
+
]
|
|
1845
|
+
}
|
|
1846
|
+
);
|
|
1847
|
+
}
|
|
1848
|
+
return /* @__PURE__ */ jsxs(
|
|
1849
|
+
"div",
|
|
1850
|
+
{
|
|
1851
|
+
ref: rowRef,
|
|
1852
|
+
className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5",
|
|
1853
|
+
children: [
|
|
1854
|
+
/* @__PURE__ */ jsxs(
|
|
1855
|
+
"div",
|
|
1856
|
+
{
|
|
1857
|
+
className: cn(
|
|
1858
|
+
"tabular-nums",
|
|
1859
|
+
trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
|
|
1860
|
+
),
|
|
1861
|
+
children: [
|
|
1862
|
+
"$",
|
|
1863
|
+
formatNumber(trade.price, precision)
|
|
1864
|
+
]
|
|
1865
|
+
}
|
|
1866
|
+
),
|
|
1867
|
+
/* @__PURE__ */ jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
|
|
1868
|
+
]
|
|
1869
|
+
}
|
|
1870
|
+
);
|
|
1871
|
+
}
|
|
1747
1872
|
function DepthRow({
|
|
1748
1873
|
side,
|
|
1749
1874
|
price,
|
|
1750
1875
|
amount,
|
|
1751
1876
|
depthPct,
|
|
1752
1877
|
precision,
|
|
1753
|
-
amountPrecision
|
|
1878
|
+
amountPrecision,
|
|
1879
|
+
hasUserOrder
|
|
1754
1880
|
}) {
|
|
1755
1881
|
const isAsk = side === "ask";
|
|
1756
|
-
|
|
1882
|
+
const rowRef = React9.useRef(null);
|
|
1883
|
+
useAmountChangeFlash(rowRef, amount);
|
|
1884
|
+
return /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
|
|
1757
1885
|
/* @__PURE__ */ jsx(
|
|
1758
1886
|
"div",
|
|
1759
1887
|
{
|
|
@@ -1761,9 +1889,16 @@ function DepthRow({
|
|
|
1761
1889
|
"absolute inset-y-0 right-0",
|
|
1762
1890
|
isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
|
|
1763
1891
|
),
|
|
1764
|
-
style: { width: `${clamp3(depthPct, 0, 100)}
|
|
1892
|
+
style: { width: `${clamp3(depthPct, 0, 100)}%`, transition: "width 300ms ease-out" }
|
|
1765
1893
|
}
|
|
1766
1894
|
),
|
|
1895
|
+
hasUserOrder ? /* @__PURE__ */ jsx(
|
|
1896
|
+
"span",
|
|
1897
|
+
{
|
|
1898
|
+
"aria-label": "Your order at this price",
|
|
1899
|
+
className: "absolute left-0 top-0 bottom-0 z-[2] w-[3px] rounded-r-sm bg-[#C9A227] shadow-[0_0_6px_rgba(201,162,39,0.6)]"
|
|
1900
|
+
}
|
|
1901
|
+
) : null,
|
|
1767
1902
|
/* @__PURE__ */ jsxs(
|
|
1768
1903
|
"div",
|
|
1769
1904
|
{
|
|
@@ -1783,7 +1918,7 @@ var DEPTH_ROW_HEIGHT_PX = 34;
|
|
|
1783
1918
|
var COMPACT_ROWS_VISIBLE = 5;
|
|
1784
1919
|
var COMPACT_ROW_HEIGHT_PX = 30;
|
|
1785
1920
|
var COMPACT_BREAKPOINT_PX = 1024;
|
|
1786
|
-
var Orderbook =
|
|
1921
|
+
var Orderbook = React9.forwardRef(
|
|
1787
1922
|
({
|
|
1788
1923
|
asks,
|
|
1789
1924
|
bids,
|
|
@@ -1798,13 +1933,44 @@ var Orderbook = React5.forwardRef(
|
|
|
1798
1933
|
onTabChange,
|
|
1799
1934
|
rightHeader = /* @__PURE__ */ jsx(LoafLiquidityBadge, { className: "text-[0.6rem]" }),
|
|
1800
1935
|
variant = "auto",
|
|
1936
|
+
userOrderPrices,
|
|
1937
|
+
isLoading = false,
|
|
1801
1938
|
className,
|
|
1802
1939
|
...props
|
|
1803
1940
|
}, ref) => {
|
|
1804
|
-
const [tab, setTab] =
|
|
1805
|
-
const [tradeFilter, setTradeFilter] =
|
|
1941
|
+
const [tab, setTab] = React9.useState(defaultTab);
|
|
1942
|
+
const [tradeFilter, setTradeFilter] = React9.useState("all");
|
|
1806
1943
|
const viewportCompact = useViewportCompact(COMPACT_BREAKPOINT_PX);
|
|
1807
|
-
|
|
1944
|
+
const { userAskPrices, userBidPrices } = React9.useMemo(() => {
|
|
1945
|
+
const ask = /* @__PURE__ */ new Set();
|
|
1946
|
+
const bid = /* @__PURE__ */ new Set();
|
|
1947
|
+
if (!userOrderPrices) return { userAskPrices: ask, userBidPrices: bid };
|
|
1948
|
+
for (const entry of userOrderPrices) {
|
|
1949
|
+
if (entry.side === "SELL") ask.add(entry.price);
|
|
1950
|
+
else bid.add(entry.price);
|
|
1951
|
+
}
|
|
1952
|
+
return { userAskPrices: ask, userBidPrices: bid };
|
|
1953
|
+
}, [userOrderPrices]);
|
|
1954
|
+
const seenTradeKeysRef = React9.useRef(/* @__PURE__ */ new Set());
|
|
1955
|
+
const initializedRef = React9.useRef(false);
|
|
1956
|
+
if (!initializedRef.current && trades.length > 0) {
|
|
1957
|
+
for (let i = 0; i < trades.length; i++) {
|
|
1958
|
+
seenTradeKeysRef.current.add(getTradeKey(trades[i], i));
|
|
1959
|
+
}
|
|
1960
|
+
initializedRef.current = true;
|
|
1961
|
+
}
|
|
1962
|
+
React9.useEffect(() => {
|
|
1963
|
+
if (!initializedRef.current) return;
|
|
1964
|
+
const live = /* @__PURE__ */ new Set();
|
|
1965
|
+
for (let i = 0; i < trades.length; i++) {
|
|
1966
|
+
live.add(getTradeKey(trades[i], i));
|
|
1967
|
+
}
|
|
1968
|
+
const seen = seenTradeKeysRef.current;
|
|
1969
|
+
for (const key of seen) {
|
|
1970
|
+
if (!live.has(key)) seen.delete(key);
|
|
1971
|
+
}
|
|
1972
|
+
}, [trades]);
|
|
1973
|
+
React9.useEffect(() => {
|
|
1808
1974
|
setTab(defaultTab);
|
|
1809
1975
|
}, [defaultTab]);
|
|
1810
1976
|
const handleTab = (next) => {
|
|
@@ -1835,7 +2001,11 @@ var Orderbook = React5.forwardRef(
|
|
|
1835
2001
|
midPrice,
|
|
1836
2002
|
midChangePercent,
|
|
1837
2003
|
midClass,
|
|
1838
|
-
sectionHeight
|
|
2004
|
+
sectionHeight,
|
|
2005
|
+
userAskPrices,
|
|
2006
|
+
userBidPrices,
|
|
2007
|
+
isLoading,
|
|
2008
|
+
seenTradeKeysRef
|
|
1839
2009
|
};
|
|
1840
2010
|
return /* @__PURE__ */ jsx(
|
|
1841
2011
|
Card,
|
|
@@ -1853,6 +2023,29 @@ var Orderbook = React5.forwardRef(
|
|
|
1853
2023
|
}
|
|
1854
2024
|
);
|
|
1855
2025
|
Orderbook.displayName = "Orderbook";
|
|
2026
|
+
function SkeletonRow({ compact }) {
|
|
2027
|
+
if (compact) {
|
|
2028
|
+
return /* @__PURE__ */ jsxs(
|
|
2029
|
+
"div",
|
|
2030
|
+
{
|
|
2031
|
+
style: {
|
|
2032
|
+
display: "grid",
|
|
2033
|
+
gridTemplateColumns: "1.2fr 0.8fr",
|
|
2034
|
+
padding: "0.2rem 0",
|
|
2035
|
+
alignItems: "center"
|
|
2036
|
+
},
|
|
2037
|
+
children: [
|
|
2038
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Skeleton, { width: "60%", height: 10 }) }),
|
|
2039
|
+
/* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: /* @__PURE__ */ jsx(Skeleton, { width: "50%", height: 10 }) })
|
|
2040
|
+
]
|
|
2041
|
+
}
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
|
|
2045
|
+
/* @__PURE__ */ jsx(Skeleton, { width: "60%", height: 12 }),
|
|
2046
|
+
/* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Skeleton, { width: "50%", height: 12 }) })
|
|
2047
|
+
] });
|
|
2048
|
+
}
|
|
1856
2049
|
function DesktopOrderbookLayout({
|
|
1857
2050
|
tab,
|
|
1858
2051
|
handleTab,
|
|
@@ -1871,8 +2064,14 @@ function DesktopOrderbookLayout({
|
|
|
1871
2064
|
midPrice,
|
|
1872
2065
|
midChangePercent,
|
|
1873
2066
|
midClass,
|
|
1874
|
-
sectionHeight
|
|
2067
|
+
sectionHeight,
|
|
2068
|
+
userAskPrices,
|
|
2069
|
+
userBidPrices,
|
|
2070
|
+
isLoading,
|
|
2071
|
+
seenTradeKeysRef
|
|
1875
2072
|
}) {
|
|
2073
|
+
const midRef = React9.useRef(null);
|
|
2074
|
+
useMidPriceFlash(midRef, midPrice, "#0b1a24");
|
|
1876
2075
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1877
2076
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
|
|
1878
2077
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
@@ -1956,29 +2155,20 @@ function DesktopOrderbookLayout({
|
|
|
1956
2155
|
{
|
|
1957
2156
|
className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
|
|
1958
2157
|
style: { scrollbarGutter: "stable" },
|
|
1959
|
-
children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) =>
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
formatNumber(trade.price, precision)
|
|
1974
|
-
]
|
|
1975
|
-
}
|
|
1976
|
-
),
|
|
1977
|
-
/* @__PURE__ */ jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
|
|
1978
|
-
]
|
|
1979
|
-
},
|
|
1980
|
-
`${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
|
|
1981
|
-
)) })
|
|
2158
|
+
children: isLoading && tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `trade-skel-${i}`)) }) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-10 text-center text-sm text-white/50", children: "No trades" }) : /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: tradeFiltered.map((trade, i) => {
|
|
2159
|
+
const tradeKey = getTradeKey(trade, i);
|
|
2160
|
+
return /* @__PURE__ */ jsx(
|
|
2161
|
+
TradeRow,
|
|
2162
|
+
{
|
|
2163
|
+
trade,
|
|
2164
|
+
tradeKey,
|
|
2165
|
+
precision,
|
|
2166
|
+
amountPrecision,
|
|
2167
|
+
seenTradeKeysRef
|
|
2168
|
+
},
|
|
2169
|
+
tradeKey
|
|
2170
|
+
);
|
|
2171
|
+
}) })
|
|
1982
2172
|
}
|
|
1983
2173
|
) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col min-h-0", children: [
|
|
1984
2174
|
/* @__PURE__ */ jsx(
|
|
@@ -1986,7 +2176,7 @@ function DesktopOrderbookLayout({
|
|
|
1986
2176
|
{
|
|
1987
2177
|
className: "flex flex-col justify-end divide-y divide-white/5 overflow-y-auto",
|
|
1988
2178
|
style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
|
|
1989
|
-
children:
|
|
2179
|
+
children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `ask-skel-${i}`)) : asks.map((l) => /* @__PURE__ */ jsx(
|
|
1990
2180
|
DepthRow,
|
|
1991
2181
|
{
|
|
1992
2182
|
side: "ask",
|
|
@@ -1994,30 +2184,38 @@ function DesktopOrderbookLayout({
|
|
|
1994
2184
|
amount: l.amount,
|
|
1995
2185
|
depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
|
|
1996
2186
|
precision,
|
|
1997
|
-
amountPrecision
|
|
2187
|
+
amountPrecision,
|
|
2188
|
+
hasUserOrder: userAskPrices.has(l.price)
|
|
1998
2189
|
},
|
|
1999
|
-
`ask-${
|
|
2190
|
+
`ask-${l.price}`
|
|
2000
2191
|
))
|
|
2001
2192
|
}
|
|
2002
2193
|
),
|
|
2003
|
-
/* @__PURE__ */ jsxs(
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2194
|
+
/* @__PURE__ */ jsxs(
|
|
2195
|
+
"div",
|
|
2196
|
+
{
|
|
2197
|
+
ref: midRef,
|
|
2198
|
+
className: "grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2",
|
|
2199
|
+
children: [
|
|
2200
|
+
/* @__PURE__ */ jsx("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: isLoading ? /* @__PURE__ */ jsx(Skeleton, { width: 110, height: 20 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2201
|
+
"$",
|
|
2202
|
+
formatNumber(midPrice, precision),
|
|
2203
|
+
midChangePercent == null ? null : /* @__PURE__ */ jsxs("span", { className: cn("ml-2 text-sm font-semibold tabular-nums", midClass), children: [
|
|
2204
|
+
midChangePercent >= 0 ? "+" : "",
|
|
2205
|
+
midChangePercent.toFixed(2),
|
|
2206
|
+
"%"
|
|
2207
|
+
] })
|
|
2208
|
+
] }) }),
|
|
2209
|
+
/* @__PURE__ */ jsx("div", {})
|
|
2210
|
+
]
|
|
2211
|
+
}
|
|
2212
|
+
),
|
|
2015
2213
|
/* @__PURE__ */ jsx(
|
|
2016
2214
|
"div",
|
|
2017
2215
|
{
|
|
2018
2216
|
className: "divide-y divide-white/5 overflow-y-auto",
|
|
2019
2217
|
style: { height: `${sectionHeight}px`, scrollbarGutter: "stable" },
|
|
2020
|
-
children:
|
|
2218
|
+
children: isLoading ? Array.from({ length: LEVEL_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, {}, `bid-skel-${i}`)) : bids.map((l) => /* @__PURE__ */ jsx(
|
|
2021
2219
|
DepthRow,
|
|
2022
2220
|
{
|
|
2023
2221
|
side: "bid",
|
|
@@ -2025,9 +2223,10 @@ function DesktopOrderbookLayout({
|
|
|
2025
2223
|
amount: l.amount,
|
|
2026
2224
|
depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
|
|
2027
2225
|
precision,
|
|
2028
|
-
amountPrecision
|
|
2226
|
+
amountPrecision,
|
|
2227
|
+
hasUserOrder: userBidPrices.has(l.price)
|
|
2029
2228
|
},
|
|
2030
|
-
`bid-${
|
|
2229
|
+
`bid-${l.price}`
|
|
2031
2230
|
))
|
|
2032
2231
|
}
|
|
2033
2232
|
)
|
|
@@ -2053,10 +2252,16 @@ function MobileOrderbookLayout({
|
|
|
2053
2252
|
midPrice,
|
|
2054
2253
|
midChangePercent,
|
|
2055
2254
|
midClass,
|
|
2056
|
-
sectionHeight: _sectionHeight
|
|
2255
|
+
sectionHeight: _sectionHeight,
|
|
2256
|
+
userAskPrices,
|
|
2257
|
+
userBidPrices,
|
|
2258
|
+
isLoading,
|
|
2259
|
+
seenTradeKeysRef
|
|
2057
2260
|
}) {
|
|
2058
|
-
const
|
|
2059
|
-
|
|
2261
|
+
const midRef = React9.useRef(null);
|
|
2262
|
+
useMidPriceFlash(midRef, midPrice, "transparent");
|
|
2263
|
+
const visibleAsks = React9.useMemo(() => asks.slice(0, COMPACT_ROWS_VISIBLE), [asks]);
|
|
2264
|
+
const visibleBids = React9.useMemo(() => bids.slice(0, COMPACT_ROWS_VISIBLE), [bids]);
|
|
2060
2265
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2061
2266
|
/* @__PURE__ */ jsx("div", { className: "px-3 pt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2062
2267
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -2125,7 +2330,7 @@ function MobileOrderbookLayout({
|
|
|
2125
2330
|
]
|
|
2126
2331
|
}
|
|
2127
2332
|
),
|
|
2128
|
-
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children:
|
|
2333
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-ask-skel-${i}`)) : visibleAsks.map((l) => /* @__PURE__ */ jsx(
|
|
2129
2334
|
MobileDepthRow,
|
|
2130
2335
|
{
|
|
2131
2336
|
side: "ask",
|
|
@@ -2133,13 +2338,15 @@ function MobileOrderbookLayout({
|
|
|
2133
2338
|
amount: l.amount,
|
|
2134
2339
|
depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
|
|
2135
2340
|
precision,
|
|
2136
|
-
amountPrecision
|
|
2341
|
+
amountPrecision,
|
|
2342
|
+
hasUserOrder: userAskPrices.has(l.price)
|
|
2137
2343
|
},
|
|
2138
|
-
`mobile-ask-${
|
|
2344
|
+
`mobile-ask-${l.price}`
|
|
2139
2345
|
)) }),
|
|
2140
2346
|
/* @__PURE__ */ jsxs(
|
|
2141
2347
|
"div",
|
|
2142
2348
|
{
|
|
2349
|
+
ref: midRef,
|
|
2143
2350
|
className: "grid",
|
|
2144
2351
|
style: {
|
|
2145
2352
|
gridTemplateColumns: "1.2fr 0.8fr",
|
|
@@ -2149,12 +2356,12 @@ function MobileOrderbookLayout({
|
|
|
2149
2356
|
borderBottom: "1px solid rgba(255,255,255,0.1)"
|
|
2150
2357
|
},
|
|
2151
2358
|
children: [
|
|
2152
|
-
/* @__PURE__ */
|
|
2359
|
+
/* @__PURE__ */ jsx(
|
|
2153
2360
|
"div",
|
|
2154
2361
|
{
|
|
2155
2362
|
style: { fontWeight: "bold", display: "flex", alignItems: "center", gap: "8px" },
|
|
2156
2363
|
className: midClass,
|
|
2157
|
-
children: [
|
|
2364
|
+
children: isLoading ? /* @__PURE__ */ jsx(Skeleton, { width: 90, height: 16 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2158
2365
|
"$",
|
|
2159
2366
|
formatNumber(midPrice, precision),
|
|
2160
2367
|
midChangePercent != null && /* @__PURE__ */ jsxs("span", { className: cn("text-[0.75rem] font-semibold tabular-nums", midClass), children: [
|
|
@@ -2162,14 +2369,14 @@ function MobileOrderbookLayout({
|
|
|
2162
2369
|
midChangePercent.toFixed(2),
|
|
2163
2370
|
"%"
|
|
2164
2371
|
] })
|
|
2165
|
-
]
|
|
2372
|
+
] })
|
|
2166
2373
|
}
|
|
2167
2374
|
),
|
|
2168
2375
|
/* @__PURE__ */ jsx("div", {})
|
|
2169
2376
|
]
|
|
2170
2377
|
}
|
|
2171
2378
|
),
|
|
2172
|
-
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children:
|
|
2379
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column" }, children: isLoading ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-bid-skel-${i}`)) : visibleBids.map((l) => /* @__PURE__ */ jsx(
|
|
2173
2380
|
MobileDepthRow,
|
|
2174
2381
|
{
|
|
2175
2382
|
side: "bid",
|
|
@@ -2177,9 +2384,10 @@ function MobileOrderbookLayout({
|
|
|
2177
2384
|
amount: l.amount,
|
|
2178
2385
|
depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
|
|
2179
2386
|
precision,
|
|
2180
|
-
amountPrecision
|
|
2387
|
+
amountPrecision,
|
|
2388
|
+
hasUserOrder: userBidPrices.has(l.price)
|
|
2181
2389
|
},
|
|
2182
|
-
`mobile-bid-${
|
|
2390
|
+
`mobile-bid-${l.price}`
|
|
2183
2391
|
)) })
|
|
2184
2392
|
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden px-3 pb-2", children: [
|
|
2185
2393
|
/* @__PURE__ */ jsxs(
|
|
@@ -2193,27 +2401,21 @@ function MobileOrderbookLayout({
|
|
|
2193
2401
|
]
|
|
2194
2402
|
}
|
|
2195
2403
|
),
|
|
2196
|
-
/* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) =>
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
),
|
|
2212
|
-
/* @__PURE__ */ jsx("div", { style: { textAlign: "right", paddingRight: "0.5rem" }, children: formatNumber(trade.amount, amountPrecision) })
|
|
2213
|
-
]
|
|
2214
|
-
},
|
|
2215
|
-
`${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`
|
|
2216
|
-
)) })
|
|
2404
|
+
/* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", minHeight: 0 }, children: isLoading && tradeFiltered.length === 0 ? Array.from({ length: COMPACT_ROWS_VISIBLE }).map((_, i) => /* @__PURE__ */ jsx(SkeletonRow, { compact: true }, `m-trade-skel-${i}`)) : tradeFiltered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-6 text-center text-[0.7rem] text-white/50", children: "No trades" }) : tradeFiltered.map((trade, i) => {
|
|
2405
|
+
const tradeKey = getTradeKey(trade, i);
|
|
2406
|
+
return /* @__PURE__ */ jsx(
|
|
2407
|
+
TradeRow,
|
|
2408
|
+
{
|
|
2409
|
+
trade,
|
|
2410
|
+
tradeKey,
|
|
2411
|
+
precision,
|
|
2412
|
+
amountPrecision,
|
|
2413
|
+
seenTradeKeysRef,
|
|
2414
|
+
compact: true
|
|
2415
|
+
},
|
|
2416
|
+
tradeKey
|
|
2417
|
+
);
|
|
2418
|
+
}) })
|
|
2217
2419
|
] })
|
|
2218
2420
|
] });
|
|
2219
2421
|
}
|
|
@@ -2223,12 +2425,16 @@ function MobileDepthRow({
|
|
|
2223
2425
|
amount,
|
|
2224
2426
|
depthPct,
|
|
2225
2427
|
precision,
|
|
2226
|
-
amountPrecision
|
|
2428
|
+
amountPrecision,
|
|
2429
|
+
hasUserOrder
|
|
2227
2430
|
}) {
|
|
2228
2431
|
const isAsk = side === "ask";
|
|
2432
|
+
const rowRef = React9.useRef(null);
|
|
2433
|
+
useAmountChangeFlash(rowRef, amount);
|
|
2229
2434
|
return /* @__PURE__ */ jsxs(
|
|
2230
2435
|
"div",
|
|
2231
2436
|
{
|
|
2437
|
+
ref: rowRef,
|
|
2232
2438
|
style: {
|
|
2233
2439
|
display: "grid",
|
|
2234
2440
|
gridTemplateColumns: "1.2fr 0.8fr",
|
|
@@ -2237,6 +2443,24 @@ function MobileDepthRow({
|
|
|
2237
2443
|
position: "relative"
|
|
2238
2444
|
},
|
|
2239
2445
|
children: [
|
|
2446
|
+
hasUserOrder ? /* @__PURE__ */ jsx(
|
|
2447
|
+
"span",
|
|
2448
|
+
{
|
|
2449
|
+
"aria-label": "Your order at this price",
|
|
2450
|
+
style: {
|
|
2451
|
+
position: "absolute",
|
|
2452
|
+
left: 0,
|
|
2453
|
+
top: 0,
|
|
2454
|
+
bottom: 0,
|
|
2455
|
+
width: "3px",
|
|
2456
|
+
backgroundColor: "#C9A227",
|
|
2457
|
+
boxShadow: "0 0 6px rgba(201,162,39,0.6)",
|
|
2458
|
+
borderTopRightRadius: "2px",
|
|
2459
|
+
borderBottomRightRadius: "2px",
|
|
2460
|
+
zIndex: 2
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
) : null,
|
|
2240
2464
|
/* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1, color: isAsk ? "#f6465d" : "#0ecb81" }, children: [
|
|
2241
2465
|
"$",
|
|
2242
2466
|
formatNumber(price, precision)
|
|
@@ -2253,7 +2477,8 @@ function MobileDepthRow({
|
|
|
2253
2477
|
width: `${clamp3(depthPct, 0, 100)}%`,
|
|
2254
2478
|
backgroundColor: isAsk ? "#f6465d" : "#0ecb81",
|
|
2255
2479
|
opacity: 0.1,
|
|
2256
|
-
zIndex: 0
|
|
2480
|
+
zIndex: 0,
|
|
2481
|
+
transition: "width 300ms ease-out"
|
|
2257
2482
|
}
|
|
2258
2483
|
}
|
|
2259
2484
|
)
|
|
@@ -2261,7 +2486,7 @@ function MobileDepthRow({
|
|
|
2261
2486
|
}
|
|
2262
2487
|
);
|
|
2263
2488
|
}
|
|
2264
|
-
var PropertyTour =
|
|
2489
|
+
var PropertyTour = React9.forwardRef(
|
|
2265
2490
|
({
|
|
2266
2491
|
className,
|
|
2267
2492
|
title,
|
|
@@ -2274,8 +2499,8 @@ var PropertyTour = React5.forwardRef(
|
|
|
2274
2499
|
playsInline = true,
|
|
2275
2500
|
...props
|
|
2276
2501
|
}, ref) => {
|
|
2277
|
-
const videoRef =
|
|
2278
|
-
|
|
2502
|
+
const videoRef = React9.useRef(null);
|
|
2503
|
+
React9.useEffect(() => {
|
|
2279
2504
|
const video = videoRef.current;
|
|
2280
2505
|
if (!video) return;
|
|
2281
2506
|
const handleFullscreenChange = () => {
|
|
@@ -2407,7 +2632,7 @@ var formatTimeAgo = (timestamp) => {
|
|
|
2407
2632
|
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
|
|
2408
2633
|
return `${Math.floor(diff / 3600)}h ago`;
|
|
2409
2634
|
};
|
|
2410
|
-
var PropertyNewsUpdates =
|
|
2635
|
+
var PropertyNewsUpdates = React9.forwardRef(
|
|
2411
2636
|
({
|
|
2412
2637
|
className,
|
|
2413
2638
|
heading,
|
|
@@ -2424,15 +2649,15 @@ var PropertyNewsUpdates = React5.forwardRef(
|
|
|
2424
2649
|
const isPurchaseVariant = variant === "purchases";
|
|
2425
2650
|
const isHomeVariant = variant === "home";
|
|
2426
2651
|
const resolvedHeading = heading ?? (isPurchaseVariant ? "Live Purchases" : "Property News & Headlines");
|
|
2427
|
-
const [homeTab, setHomeTab] =
|
|
2652
|
+
const [homeTab, setHomeTab] = React9.useState("all");
|
|
2428
2653
|
const purchaseItems = purchasesProp ?? [];
|
|
2429
|
-
const [page, setPage] =
|
|
2430
|
-
|
|
2654
|
+
const [page, setPage] = React9.useState(0);
|
|
2655
|
+
React9.useEffect(() => {
|
|
2431
2656
|
ensureAnimationsInjected();
|
|
2432
2657
|
}, []);
|
|
2433
2658
|
const hasItems = Array.isArray(items) && items.length > 0;
|
|
2434
|
-
const totalPages =
|
|
2435
|
-
|
|
2659
|
+
const totalPages = React9.useMemo(() => hasItems ? Math.max(1, Math.ceil(items.length / ITEMS_PER_PAGE)) : 1, [hasItems, items.length]);
|
|
2660
|
+
React9.useEffect(() => {
|
|
2436
2661
|
setPage((prev) => Math.min(prev, totalPages - 1));
|
|
2437
2662
|
}, [totalPages]);
|
|
2438
2663
|
const paginatedItems = hasItems ? items.slice(page * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE + ITEMS_PER_PAGE) : [];
|
|
@@ -2740,7 +2965,7 @@ var defaultFormat = (value) => new Intl.NumberFormat("en-US", {
|
|
|
2740
2965
|
notation: value >= 1e5 ? "compact" : "standard",
|
|
2741
2966
|
maximumFractionDigits: value >= 1e3 ? 0 : 2
|
|
2742
2967
|
}).format(value);
|
|
2743
|
-
var TradingSlider =
|
|
2968
|
+
var TradingSlider = React9.forwardRef(
|
|
2744
2969
|
({
|
|
2745
2970
|
label = "Trade size",
|
|
2746
2971
|
helperText = "Drag to pick the desired notional.",
|
|
@@ -2758,7 +2983,7 @@ var TradingSlider = React5.forwardRef(
|
|
|
2758
2983
|
...rest
|
|
2759
2984
|
}, ref) => {
|
|
2760
2985
|
const isControlled = value !== void 0;
|
|
2761
|
-
const [internalValue, setInternalValue] =
|
|
2986
|
+
const [internalValue, setInternalValue] = React9.useState(
|
|
2762
2987
|
defaultValue ?? (typeof min === "number" ? min : 0)
|
|
2763
2988
|
);
|
|
2764
2989
|
const currentValue = isControlled ? Number(value) : internalValue;
|
|
@@ -2861,7 +3086,7 @@ var MobileToggleButton = styled24.button`
|
|
|
2861
3086
|
padding: 0.6rem 0.5rem;
|
|
2862
3087
|
}
|
|
2863
3088
|
`;
|
|
2864
|
-
var MobileTradeNav =
|
|
3089
|
+
var MobileTradeNav = React9.forwardRef(
|
|
2865
3090
|
({ className, items, activeId, onChange, ...props }, ref) => {
|
|
2866
3091
|
return /* @__PURE__ */ jsx(MobileToggleContainer, { ref, className: cn(className), ...props, children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
2867
3092
|
MobileToggleButton,
|
|
@@ -3512,7 +3737,7 @@ var formatPercent = (value, fractionDigits = 2) => {
|
|
|
3512
3737
|
if (value == null || Number.isNaN(value)) return "\u2014";
|
|
3513
3738
|
return `${value.toFixed(fractionDigits)}%`;
|
|
3514
3739
|
};
|
|
3515
|
-
var YourOrders =
|
|
3740
|
+
var YourOrders = React9.forwardRef(
|
|
3516
3741
|
({
|
|
3517
3742
|
className,
|
|
3518
3743
|
title,
|
|
@@ -3525,10 +3750,10 @@ var YourOrders = React5.forwardRef(
|
|
|
3525
3750
|
pageSize: pageSizeOverride,
|
|
3526
3751
|
...props
|
|
3527
3752
|
}, ref) => {
|
|
3528
|
-
const [internalActiveTab, setInternalActiveTab] =
|
|
3529
|
-
const [page, setPage] =
|
|
3753
|
+
const [internalActiveTab, setInternalActiveTab] = React9.useState(tabs?.[0]?.id ?? "portfolio");
|
|
3754
|
+
const [page, setPage] = React9.useState(0);
|
|
3530
3755
|
const effectiveActiveTabId = activeTabId ?? internalActiveTab;
|
|
3531
|
-
|
|
3756
|
+
React9.useEffect(() => {
|
|
3532
3757
|
setPage(0);
|
|
3533
3758
|
}, [effectiveActiveTabId]);
|
|
3534
3759
|
const handleTabChange = (tabId) => {
|
|
@@ -3910,7 +4135,7 @@ function createCandlestickSeries(chart, options) {
|
|
|
3910
4135
|
}
|
|
3911
4136
|
throw new Error("Candlestick series API is not available in the current lightweight-charts version.");
|
|
3912
4137
|
}
|
|
3913
|
-
var PriceChart =
|
|
4138
|
+
var PriceChart = React9.forwardRef(
|
|
3914
4139
|
({
|
|
3915
4140
|
className,
|
|
3916
4141
|
title = "Price Chart",
|
|
@@ -3924,18 +4149,18 @@ var PriceChart = React5.forwardRef(
|
|
|
3924
4149
|
height = 301.52,
|
|
3925
4150
|
...props
|
|
3926
4151
|
}, ref) => {
|
|
3927
|
-
const containerRef =
|
|
3928
|
-
const chartRef =
|
|
3929
|
-
const seriesRef =
|
|
3930
|
-
const priceLineRef =
|
|
3931
|
-
const [hoveredRange, setHoveredRange] =
|
|
3932
|
-
const [dropdownOpen, setDropdownOpen] =
|
|
3933
|
-
const dropdownRef =
|
|
3934
|
-
const isAutoScrollRef =
|
|
4152
|
+
const containerRef = React9.useRef(null);
|
|
4153
|
+
const chartRef = React9.useRef(null);
|
|
4154
|
+
const seriesRef = React9.useRef(null);
|
|
4155
|
+
const priceLineRef = React9.useRef(null);
|
|
4156
|
+
const [hoveredRange, setHoveredRange] = React9.useState(null);
|
|
4157
|
+
const [dropdownOpen, setDropdownOpen] = React9.useState(false);
|
|
4158
|
+
const dropdownRef = React9.useRef(null);
|
|
4159
|
+
const isAutoScrollRef = React9.useRef(true);
|
|
3935
4160
|
const visibleRanges = ranges.slice(0, VISIBLE_RANGE_COUNT);
|
|
3936
4161
|
const dropdownRanges = ranges.slice(VISIBLE_RANGE_COUNT);
|
|
3937
4162
|
const selectedInDropdown = dropdownRanges.includes(selectedRange);
|
|
3938
|
-
|
|
4163
|
+
React9.useEffect(() => {
|
|
3939
4164
|
const handleClickOutside = (e) => {
|
|
3940
4165
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
3941
4166
|
setDropdownOpen(false);
|
|
@@ -3944,25 +4169,25 @@ var PriceChart = React5.forwardRef(
|
|
|
3944
4169
|
document.addEventListener("mousedown", handleClickOutside);
|
|
3945
4170
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
3946
4171
|
}, []);
|
|
3947
|
-
const resolvedPrice =
|
|
4172
|
+
const resolvedPrice = React9.useMemo(() => {
|
|
3948
4173
|
if (price != null) return price;
|
|
3949
4174
|
const last = data.at(-1);
|
|
3950
4175
|
return last?.close;
|
|
3951
4176
|
}, [data, price]);
|
|
3952
|
-
const inferredChangePercent =
|
|
4177
|
+
const inferredChangePercent = React9.useMemo(() => {
|
|
3953
4178
|
if (changePercent != null) return changePercent;
|
|
3954
4179
|
const first = data[0]?.open;
|
|
3955
4180
|
const last = data.at(-1)?.close;
|
|
3956
4181
|
if (first == null || last == null || first === 0) return void 0;
|
|
3957
4182
|
return (last - first) / first * 100;
|
|
3958
4183
|
}, [changePercent, data]);
|
|
3959
|
-
const dollarChange =
|
|
4184
|
+
const dollarChange = React9.useMemo(() => {
|
|
3960
4185
|
const first = data[0]?.open;
|
|
3961
4186
|
const last = data.at(-1)?.close;
|
|
3962
4187
|
if (first == null || last == null) return void 0;
|
|
3963
4188
|
return last - first;
|
|
3964
4189
|
}, [data]);
|
|
3965
|
-
|
|
4190
|
+
React9.useEffect(() => {
|
|
3966
4191
|
const el = containerRef.current;
|
|
3967
4192
|
if (!el) return;
|
|
3968
4193
|
const chart = LightweightCharts.createChart(el, {
|
|
@@ -4007,7 +4232,7 @@ var PriceChart = React5.forwardRef(
|
|
|
4007
4232
|
chart.remove();
|
|
4008
4233
|
};
|
|
4009
4234
|
}, []);
|
|
4010
|
-
|
|
4235
|
+
React9.useEffect(() => {
|
|
4011
4236
|
const chart = chartRef.current;
|
|
4012
4237
|
if (!chart) return;
|
|
4013
4238
|
const effectiveRange = selectedRange ?? ranges?.[0] ?? "1D";
|
|
@@ -4015,7 +4240,7 @@ var PriceChart = React5.forwardRef(
|
|
|
4015
4240
|
timeScale: getTimeScaleOptions(effectiveRange)
|
|
4016
4241
|
});
|
|
4017
4242
|
}, [selectedRange, ranges]);
|
|
4018
|
-
|
|
4243
|
+
React9.useEffect(() => {
|
|
4019
4244
|
const chart = chartRef.current;
|
|
4020
4245
|
const series = seriesRef.current;
|
|
4021
4246
|
if (!chart || !series) return;
|
|
@@ -4220,7 +4445,7 @@ var formatPrice3 = (value, currencySymbol) => {
|
|
|
4220
4445
|
maximumFractionDigits: 3
|
|
4221
4446
|
})}`;
|
|
4222
4447
|
};
|
|
4223
|
-
var PropertyHeroHeader =
|
|
4448
|
+
var PropertyHeroHeader = React9.forwardRef(
|
|
4224
4449
|
({
|
|
4225
4450
|
className,
|
|
4226
4451
|
imageUrl,
|
|
@@ -4241,14 +4466,15 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4241
4466
|
makeOfferDisabled = false,
|
|
4242
4467
|
hideMakeOfferButton = false,
|
|
4243
4468
|
statusBadge,
|
|
4469
|
+
isLoading = false,
|
|
4244
4470
|
...props
|
|
4245
4471
|
}, ref) => {
|
|
4246
4472
|
const isPositive = changePercent == null ? void 0 : changePercent >= 0;
|
|
4247
4473
|
const accentColor = "#e6c87e";
|
|
4248
4474
|
const tradeHoverColor = "#f5dd9a";
|
|
4249
|
-
const [isTradeInteracting, setIsTradeInteracting] =
|
|
4250
|
-
const [isOfferInteracting, setIsOfferInteracting] =
|
|
4251
|
-
const hasAmenities = beds != null || baths != null || cars != null || propertyTypeLabel != null;
|
|
4475
|
+
const [isTradeInteracting, setIsTradeInteracting] = React9.useState(false);
|
|
4476
|
+
const [isOfferInteracting, setIsOfferInteracting] = React9.useState(false);
|
|
4477
|
+
const hasAmenities = isLoading || beds != null || baths != null || cars != null || propertyTypeLabel != null;
|
|
4252
4478
|
const isTradeDisabled = !onTrade;
|
|
4253
4479
|
const isMakeOfferButtonDisabled = makeOfferDisabled || !onMakeOffer;
|
|
4254
4480
|
const showMakeOfferButton = !hideMakeOfferButton;
|
|
@@ -4288,7 +4514,7 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4288
4514
|
/* @__PURE__ */ jsx("h1", { style: headingStyle, className: "break-words", children: name }),
|
|
4289
4515
|
/* @__PURE__ */ jsxs(InfoRow, { className: "mb-3 max-[768px]:mb-[0.6rem] max-[480px]:mb-[0.5rem]", children: [
|
|
4290
4516
|
/* @__PURE__ */ jsx(LocationText, { children: location }),
|
|
4291
|
-
price == null ? null : /* @__PURE__ */ jsxs(PriceBlock, { children: [
|
|
4517
|
+
isLoading ? /* @__PURE__ */ jsx(PriceBlock, { children: /* @__PURE__ */ jsx(Skeleton, { width: 110, height: 18 }) }) : price == null ? null : /* @__PURE__ */ jsxs(PriceBlock, { children: [
|
|
4292
4518
|
formatPrice3(price, currencySymbol),
|
|
4293
4519
|
changePercent == null ? null : /* @__PURE__ */ jsxs(
|
|
4294
4520
|
"span",
|
|
@@ -4318,7 +4544,21 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4318
4544
|
] })
|
|
4319
4545
|
] })
|
|
4320
4546
|
] }),
|
|
4321
|
-
/* @__PURE__ */
|
|
4547
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4548
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
4549
|
+
/* @__PURE__ */ jsx(BedDouble, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4550
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 52, height: 14 })
|
|
4551
|
+
] }),
|
|
4552
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
4553
|
+
/* @__PURE__ */ jsx(Bath, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4554
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 56, height: 14 })
|
|
4555
|
+
] }),
|
|
4556
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
4557
|
+
/* @__PURE__ */ jsx(CarFront, { className: "mr-2 h-[18px] w-[18px] opacity-60" }),
|
|
4558
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 50, height: 14 })
|
|
4559
|
+
] }),
|
|
4560
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 60, height: 14 })
|
|
4561
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4322
4562
|
beds == null ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
4323
4563
|
/* @__PURE__ */ jsx(BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
|
|
4324
4564
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
@@ -4341,7 +4581,7 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4341
4581
|
] })
|
|
4342
4582
|
] }),
|
|
4343
4583
|
propertyTypeLabel == null ? null : /* @__PURE__ */ jsx("div", { children: propertyTypeLabel })
|
|
4344
|
-
] })
|
|
4584
|
+
] }) })
|
|
4345
4585
|
] }),
|
|
4346
4586
|
/* @__PURE__ */ jsxs(ActionButtons, { children: [
|
|
4347
4587
|
/* @__PURE__ */ jsx(
|
|
@@ -4403,7 +4643,21 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4403
4643
|
] })
|
|
4404
4644
|
] }) })
|
|
4405
4645
|
] }),
|
|
4406
|
-
hasAmenities ? /* @__PURE__ */
|
|
4646
|
+
hasAmenities ? /* @__PURE__ */ jsx(MobileAmenities, { children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4647
|
+
/* @__PURE__ */ jsxs(MobileAmenity, { children: [
|
|
4648
|
+
/* @__PURE__ */ jsx(BedDouble, { className: "h-4 w-4 opacity-60" }),
|
|
4649
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 40, height: 12 })
|
|
4650
|
+
] }),
|
|
4651
|
+
/* @__PURE__ */ jsxs(MobileAmenity, { children: [
|
|
4652
|
+
/* @__PURE__ */ jsx(Bath, { className: "h-4 w-4 opacity-60" }),
|
|
4653
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 44, height: 12 })
|
|
4654
|
+
] }),
|
|
4655
|
+
/* @__PURE__ */ jsxs(MobileAmenity, { children: [
|
|
4656
|
+
/* @__PURE__ */ jsx(CarFront, { className: "h-4 w-4 opacity-60" }),
|
|
4657
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 42, height: 12 })
|
|
4658
|
+
] }),
|
|
4659
|
+
/* @__PURE__ */ jsx(MobileAmenity, { children: /* @__PURE__ */ jsx(Skeleton, { width: 52, height: 12 }) })
|
|
4660
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4407
4661
|
beds == null ? null : /* @__PURE__ */ jsxs(MobileAmenity, { children: [
|
|
4408
4662
|
/* @__PURE__ */ jsx(BedDouble, { className: "h-4 w-4" }),
|
|
4409
4663
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
@@ -4426,7 +4680,7 @@ var PropertyHeroHeader = React5.forwardRef(
|
|
|
4426
4680
|
] })
|
|
4427
4681
|
] }),
|
|
4428
4682
|
propertyTypeLabel == null ? null : /* @__PURE__ */ jsx(MobileAmenity, { children: propertyTypeLabel })
|
|
4429
|
-
] }) : null
|
|
4683
|
+
] }) }) : null
|
|
4430
4684
|
] });
|
|
4431
4685
|
}
|
|
4432
4686
|
);
|
|
@@ -4668,6 +4922,15 @@ var Header = ({
|
|
|
4668
4922
|
const [isMoreMenuOpen, setIsMoreMenuOpen] = useState(false);
|
|
4669
4923
|
const [showLoginPopup, setShowLoginPopup] = useState(false);
|
|
4670
4924
|
const [loginPopupInitialView, setLoginPopupInitialView] = useState(void 0);
|
|
4925
|
+
useEffect(() => {
|
|
4926
|
+
if (typeof window === "undefined") return;
|
|
4927
|
+
const ua = navigator.userAgent;
|
|
4928
|
+
const isTelegram = /Telegram/i.test(ua);
|
|
4929
|
+
const isIOS = /iPhone|iPad|iPod/.test(ua);
|
|
4930
|
+
if (isTelegram && isIOS) {
|
|
4931
|
+
document.documentElement.style.setProperty("--telegram-safe-top", "59px");
|
|
4932
|
+
}
|
|
4933
|
+
}, []);
|
|
4671
4934
|
useEffect(() => {
|
|
4672
4935
|
const handleClickOutside = (event) => {
|
|
4673
4936
|
const target = event.target;
|
|
@@ -4818,7 +5081,7 @@ var Header = ({
|
|
|
4818
5081
|
setShowLoginPopup(true);
|
|
4819
5082
|
}
|
|
4820
5083
|
};
|
|
4821
|
-
const handleLoginPopupClose =
|
|
5084
|
+
const handleLoginPopupClose = React9__default.useCallback(() => {
|
|
4822
5085
|
setShowLoginPopup(false);
|
|
4823
5086
|
setLoginPopupInitialView(void 0);
|
|
4824
5087
|
}, []);
|
|
@@ -5106,8 +5369,8 @@ var SafeAreaCover = styled24.div`
|
|
|
5106
5369
|
top: 0;
|
|
5107
5370
|
left: 0;
|
|
5108
5371
|
right: 0;
|
|
5109
|
-
height: env(safe-area-inset-top, 0px);
|
|
5110
|
-
min-height: env(safe-area-inset-top, 0px);
|
|
5372
|
+
height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5373
|
+
min-height: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5111
5374
|
background-color: #0d1117;
|
|
5112
5375
|
z-index: 1001;
|
|
5113
5376
|
pointer-events: none;
|
|
@@ -5161,7 +5424,7 @@ var HeaderContainer = styled24.header`
|
|
|
5161
5424
|
/* Split padding so browsers that don't support env() inside shorthand
|
|
5162
5425
|
still get the horizontal padding — only the top falls back to 0 */
|
|
5163
5426
|
padding: 0 2rem;
|
|
5164
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5427
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5165
5428
|
background-color: #0d1117;
|
|
5166
5429
|
border-bottom: 1px solid #232a32;
|
|
5167
5430
|
position: fixed;
|
|
@@ -5172,18 +5435,18 @@ var HeaderContainer = styled24.header`
|
|
|
5172
5435
|
width: 100%;
|
|
5173
5436
|
/* Fallback min-height for browsers that can't evaluate calc+env */
|
|
5174
5437
|
min-height: 56px;
|
|
5175
|
-
min-height: calc(56px + env(safe-area-inset-top, 0px));
|
|
5438
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5176
5439
|
box-sizing: border-box;
|
|
5177
5440
|
|
|
5178
5441
|
@media (max-width: 768px) {
|
|
5179
5442
|
padding: 0 1rem;
|
|
5180
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5443
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5181
5444
|
}
|
|
5182
5445
|
`;
|
|
5183
5446
|
var HeaderSpacer = styled24.div`
|
|
5184
5447
|
width: 100%;
|
|
5185
5448
|
min-height: 56px;
|
|
5186
|
-
min-height: calc(56px + env(safe-area-inset-top, 0px));
|
|
5449
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5187
5450
|
flex-shrink: 0;
|
|
5188
5451
|
`;
|
|
5189
5452
|
var Logo = styled24.div`
|
|
@@ -5238,12 +5501,12 @@ var Nav = styled24.nav`
|
|
|
5238
5501
|
@media (max-width: 1300px) {
|
|
5239
5502
|
position: fixed;
|
|
5240
5503
|
top: 56px;
|
|
5241
|
-
top: calc(56px + env(safe-area-inset-top, 0px));
|
|
5504
|
+
top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5242
5505
|
right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
|
|
5243
5506
|
width: 280px;
|
|
5244
5507
|
max-width: 280px;
|
|
5245
5508
|
height: calc(100vh - 56px);
|
|
5246
|
-
height: calc(100vh - 56px - env(safe-area-inset-top, 0px));
|
|
5509
|
+
height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5247
5510
|
background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
|
|
5248
5511
|
z-index: 1000;
|
|
5249
5512
|
transition: right 0.3s ease;
|
|
@@ -5516,10 +5779,10 @@ var MobileNavItem = styled24.div`
|
|
|
5516
5779
|
padding-left: 24px;
|
|
5517
5780
|
}
|
|
5518
5781
|
`;
|
|
5519
|
-
var PropertySubheader =
|
|
5782
|
+
var PropertySubheader = React9.forwardRef(
|
|
5520
5783
|
({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
|
|
5521
|
-
const tabsContainerRef =
|
|
5522
|
-
|
|
5784
|
+
const tabsContainerRef = React9.useRef(null);
|
|
5785
|
+
React9.useEffect(() => {
|
|
5523
5786
|
const container = tabsContainerRef.current;
|
|
5524
5787
|
if (!container) return;
|
|
5525
5788
|
const isMobile = window.innerWidth <= 768;
|
|
@@ -5675,7 +5938,7 @@ var LoginPopup = ({
|
|
|
5675
5938
|
const [fiatFundingLoading, setFiatFundingLoading] = useState(false);
|
|
5676
5939
|
const [fundingError, setFundingError] = useState("");
|
|
5677
5940
|
const [transakWidgetUrl, setTransakWidgetUrl] = useState(null);
|
|
5678
|
-
const suppressAutoCloseRef =
|
|
5941
|
+
const suppressAutoCloseRef = React9__default.useRef(false);
|
|
5679
5942
|
useEffect(() => {
|
|
5680
5943
|
if (typeof initialView === "string") {
|
|
5681
5944
|
setView(initialView);
|
|
@@ -6855,7 +7118,7 @@ var MiniLiveFeed = () => {
|
|
|
6855
7118
|
);
|
|
6856
7119
|
};
|
|
6857
7120
|
LoginPopup.displayName = "LoginPopup";
|
|
6858
|
-
var PropertyCompareBar =
|
|
7121
|
+
var PropertyCompareBar = React9.forwardRef(
|
|
6859
7122
|
({
|
|
6860
7123
|
className,
|
|
6861
7124
|
addresses,
|
|
@@ -6866,7 +7129,7 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6866
7129
|
price,
|
|
6867
7130
|
...props
|
|
6868
7131
|
}, ref) => {
|
|
6869
|
-
const normalizedAddresses =
|
|
7132
|
+
const normalizedAddresses = React9.useMemo(() => {
|
|
6870
7133
|
return addresses.map(
|
|
6871
7134
|
(option) => typeof option === "string" ? { id: option, label: option } : option
|
|
6872
7135
|
);
|
|
@@ -6874,11 +7137,11 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6874
7137
|
const hasAddresses = normalizedAddresses.length > 0;
|
|
6875
7138
|
const firstAddressId = normalizedAddresses[0]?.id;
|
|
6876
7139
|
const isControlled = selectedAddressId !== void 0;
|
|
6877
|
-
const [internalSelectedId, setInternalSelectedId] =
|
|
7140
|
+
const [internalSelectedId, setInternalSelectedId] = React9.useState(
|
|
6878
7141
|
() => isControlled ? void 0 : firstAddressId
|
|
6879
7142
|
);
|
|
6880
7143
|
const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
|
|
6881
|
-
|
|
7144
|
+
React9.useEffect(() => {
|
|
6882
7145
|
if (!isControlled) {
|
|
6883
7146
|
setInternalSelectedId((current) => {
|
|
6884
7147
|
if (current != null && normalizedAddresses.some((option) => option.id === current)) {
|
|
@@ -6889,9 +7152,9 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6889
7152
|
}
|
|
6890
7153
|
}, [firstAddressId, isControlled, normalizedAddresses]);
|
|
6891
7154
|
const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
|
|
6892
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
6893
|
-
const dropdownRef =
|
|
6894
|
-
|
|
7155
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
|
|
7156
|
+
const dropdownRef = React9.useRef(null);
|
|
7157
|
+
React9.useEffect(() => {
|
|
6895
7158
|
if (!isDropdownOpen) return;
|
|
6896
7159
|
const handleClick = (event) => {
|
|
6897
7160
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -7614,7 +7877,8 @@ function PropertyOverview({
|
|
|
7614
7877
|
bathrooms,
|
|
7615
7878
|
carSpaces,
|
|
7616
7879
|
propertyTypeLabel,
|
|
7617
|
-
tokensIssued: tokensIssuedProp
|
|
7880
|
+
tokensIssued: tokensIssuedProp,
|
|
7881
|
+
isLoading = false
|
|
7618
7882
|
}) {
|
|
7619
7883
|
const [isDescExpanded, setDescExpanded] = useState(false);
|
|
7620
7884
|
const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
|
|
@@ -7652,13 +7916,14 @@ function PropertyOverview({
|
|
|
7652
7916
|
const weeklyRent = overviewData?.weeklyRent ?? 0;
|
|
7653
7917
|
const annualRent = weeklyRent * 52;
|
|
7654
7918
|
const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
|
|
7919
|
+
const loadingSkeleton = /* @__PURE__ */ jsx(Skeleton, { width: 90, height: 18 });
|
|
7655
7920
|
const financialItems = financialItemsProp ?? [
|
|
7656
|
-
{ label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7657
|
-
{ label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7658
|
-
{ label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7659
|
-
{ label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7660
|
-
{ label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7661
|
-
{ label: "Indicative Listing", value: overviewData?.indicativeListing ?? "N/A" }
|
|
7921
|
+
{ label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7922
|
+
{ label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7923
|
+
{ label: "Weekly Rent", value: isLoading && !overviewData ? loadingSkeleton : weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7924
|
+
{ label: "Dividend Yield", value: isLoading && dividendYield == null && resolvedValuation == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7925
|
+
{ label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7926
|
+
{ label: "Indicative Listing", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.indicativeListing ?? "N/A" }
|
|
7662
7927
|
];
|
|
7663
7928
|
const galleryImages = images ?? [];
|
|
7664
7929
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -9502,6 +9767,8 @@ var formatTimeAgo2 = (timestamp) => {
|
|
|
9502
9767
|
};
|
|
9503
9768
|
function VideoActivitySection({
|
|
9504
9769
|
ipoStarted,
|
|
9770
|
+
ipoEnded = false,
|
|
9771
|
+
isLoading = false,
|
|
9505
9772
|
recentOrders = [],
|
|
9506
9773
|
ordersAllocated = 0,
|
|
9507
9774
|
tokenPrice = 0
|
|
@@ -9510,6 +9777,9 @@ function VideoActivitySection({
|
|
|
9510
9777
|
() => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
|
|
9511
9778
|
[recentOrders]
|
|
9512
9779
|
);
|
|
9780
|
+
const headerStatusText = ipoEnded ? `Sale ended${ordersAllocated > 0 ? ` \xB7 ${ordersAllocated.toLocaleString()} orders` : ""}` : ipoStarted ? isLoading && sortedOrders.length === 0 ? "Loading orders\u2026" : `Active orders: ${ordersAllocated.toLocaleString()}` : "Waiting for Offer to Open";
|
|
9781
|
+
const showSkeletonFeed = ipoStarted && isLoading && sortedOrders.length === 0;
|
|
9782
|
+
const showOrderFeed = !showSkeletonFeed && (ipoStarted || ipoEnded && sortedOrders.length > 0);
|
|
9513
9783
|
return /* @__PURE__ */ jsxs(Section3, { children: [
|
|
9514
9784
|
/* @__PURE__ */ jsxs(VideoPanel, { children: [
|
|
9515
9785
|
/* @__PURE__ */ jsx("div", { className: "section-header", children: /* @__PURE__ */ jsx("h3", { children: "Musgrave" }) }),
|
|
@@ -9521,31 +9791,40 @@ function VideoActivitySection({
|
|
|
9521
9791
|
/* @__PURE__ */ jsxs(ActivityPanel, { children: [
|
|
9522
9792
|
/* @__PURE__ */ jsxs("div", { className: "section-header", children: [
|
|
9523
9793
|
/* @__PURE__ */ jsxs("h3", { children: [
|
|
9524
|
-
/* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted }),
|
|
9794
|
+
/* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
|
|
9525
9795
|
"Recent Order Activity"
|
|
9526
9796
|
] }),
|
|
9527
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
9797
|
+
/* @__PURE__ */ jsx("span", { children: headerStatusText })
|
|
9528
9798
|
] }),
|
|
9529
|
-
/* @__PURE__ */ jsx("div", { className: "activity-content", children:
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9799
|
+
/* @__PURE__ */ jsx("div", { className: "activity-content", children: showSkeletonFeed ? /* @__PURE__ */ jsx(FeedList, { children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs(SkeletonFeedRow, { children: [
|
|
9800
|
+
/* @__PURE__ */ jsxs("div", { className: "info-col", children: [
|
|
9801
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 110, height: 14 }),
|
|
9802
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 56, height: 10 })
|
|
9803
|
+
] }),
|
|
9804
|
+
/* @__PURE__ */ jsx(Skeleton, { width: 70, height: 14 })
|
|
9805
|
+
] }, `feed-skel-${i}`)) }) : showOrderFeed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9806
|
+
ipoEnded && /* @__PURE__ */ jsx(EndedBanner, { children: "Sale ended \u2014 final allocations" }),
|
|
9807
|
+
/* @__PURE__ */ jsx(FeedList, { children: sortedOrders.map((order, index) => {
|
|
9808
|
+
const amount = tokenPrice * order.quantity;
|
|
9809
|
+
const barPercent = Math.min(85, Math.max(15, amount / MAX_DISPLAY_AMOUNT * 100));
|
|
9810
|
+
const isAlternate = index % 2 === 1;
|
|
9811
|
+
return /* @__PURE__ */ jsxs(
|
|
9812
|
+
PurchaseItem,
|
|
9813
|
+
{
|
|
9814
|
+
$barWidth: `${barPercent}%`,
|
|
9815
|
+
$isAlternate: isAlternate,
|
|
9816
|
+
children: [
|
|
9817
|
+
/* @__PURE__ */ jsxs(PurchaseInfo, { children: [
|
|
9818
|
+
/* @__PURE__ */ jsx(PurchaseName, { children: order.buyerHandle || `${order.buyerAddress.slice(0, 6)}...${order.buyerAddress.slice(-4)}` }),
|
|
9819
|
+
/* @__PURE__ */ jsx(PurchaseTime, { children: formatTimeAgo2(order.timestamp) })
|
|
9820
|
+
] }),
|
|
9821
|
+
/* @__PURE__ */ jsx(PurchaseAmount, { children: formatCurrency4(amount) })
|
|
9822
|
+
]
|
|
9823
|
+
},
|
|
9824
|
+
order.txHash
|
|
9825
|
+
);
|
|
9826
|
+
}) })
|
|
9827
|
+
] }) : ipoEnded ? /* @__PURE__ */ jsx("div", { className: "activity-empty", children: /* @__PURE__ */ jsx("p", { children: "Sale ended \u2014 no orders were placed." }) }) : /* @__PURE__ */ jsxs("div", { className: "activity-empty", children: [
|
|
9549
9828
|
/* @__PURE__ */ jsx("div", { className: "spinner" }),
|
|
9550
9829
|
/* @__PURE__ */ jsx("p", { children: "Activity will appear once the Offering opens" })
|
|
9551
9830
|
] }) })
|
|
@@ -9686,6 +9965,43 @@ var ActivityPanel = styled24.div`
|
|
|
9686
9965
|
to { transform: rotate(360deg); }
|
|
9687
9966
|
}
|
|
9688
9967
|
`;
|
|
9968
|
+
var SkeletonFeedRow = styled24.div`
|
|
9969
|
+
padding: 0.625rem 0.75rem;
|
|
9970
|
+
border-bottom: 1px solid rgba(255,255,255,0.04);
|
|
9971
|
+
display: flex;
|
|
9972
|
+
justify-content: space-between;
|
|
9973
|
+
align-items: center;
|
|
9974
|
+
gap: 1rem;
|
|
9975
|
+
|
|
9976
|
+
&:last-child {
|
|
9977
|
+
border-bottom: none;
|
|
9978
|
+
}
|
|
9979
|
+
|
|
9980
|
+
.info-col {
|
|
9981
|
+
display: flex;
|
|
9982
|
+
flex-direction: column;
|
|
9983
|
+
gap: 0.3rem;
|
|
9984
|
+
min-width: 0;
|
|
9985
|
+
flex: 1;
|
|
9986
|
+
}
|
|
9987
|
+
|
|
9988
|
+
@media (max-width: 768px) {
|
|
9989
|
+
padding: 0.4rem 0.6rem;
|
|
9990
|
+
}
|
|
9991
|
+
`;
|
|
9992
|
+
var EndedBanner = styled24.div`
|
|
9993
|
+
font-size: 0.7rem;
|
|
9994
|
+
font-weight: 600;
|
|
9995
|
+
letter-spacing: 0.04em;
|
|
9996
|
+
text-transform: uppercase;
|
|
9997
|
+
color: rgba(255, 255, 255, 0.55);
|
|
9998
|
+
background: rgba(255, 255, 255, 0.04);
|
|
9999
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
10000
|
+
border-radius: 6px;
|
|
10001
|
+
padding: 0.4rem 0.6rem;
|
|
10002
|
+
margin-bottom: 0.5rem;
|
|
10003
|
+
text-align: center;
|
|
10004
|
+
`;
|
|
9689
10005
|
var FeedList = styled24.div`
|
|
9690
10006
|
width: 100%;
|
|
9691
10007
|
overflow-y: auto;
|
|
@@ -10672,6 +10988,22 @@ function PortfolioActivityPanel({
|
|
|
10672
10988
|
return 0;
|
|
10673
10989
|
}
|
|
10674
10990
|
}, [activeTab, positions.length, offeringOrders.length, openOrders.length, orderHistory.length, tradeHistory.length, transfers.length]);
|
|
10991
|
+
const positionsCount = positions.length;
|
|
10992
|
+
const openOrdersCount = useMemo(
|
|
10993
|
+
() => openOrders.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
|
|
10994
|
+
[openOrders]
|
|
10995
|
+
);
|
|
10996
|
+
const pendingHistoryCount = useMemo(
|
|
10997
|
+
() => orderHistory.filter((o) => o.status === "OPEN" || o.status === "PARTIALLY_FILLED").length,
|
|
10998
|
+
[orderHistory]
|
|
10999
|
+
);
|
|
11000
|
+
const pendingOfferingsCount = useMemo(
|
|
11001
|
+
() => offeringOrders.filter((o) => {
|
|
11002
|
+
const s = o.status.toUpperCase();
|
|
11003
|
+
return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
|
|
11004
|
+
}).length,
|
|
11005
|
+
[offeringOrders]
|
|
11006
|
+
);
|
|
10675
11007
|
const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
|
|
10676
11008
|
const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
|
|
10677
11009
|
const handleTabChange = (tab) => {
|
|
@@ -10681,10 +11013,38 @@ function PortfolioActivityPanel({
|
|
|
10681
11013
|
return /* @__PURE__ */ jsxs(Container2, { className, style, children: [
|
|
10682
11014
|
/* @__PURE__ */ jsx(PanelTitle, { children: "Activity" }),
|
|
10683
11015
|
/* @__PURE__ */ jsxs(TabContainer, { children: [
|
|
10684
|
-
showPositionsTab && /* @__PURE__ */
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
11016
|
+
showPositionsTab && /* @__PURE__ */ jsxs(Tab, { $active: activeTab === "positions", onClick: () => handleTabChange("positions"), children: [
|
|
11017
|
+
"Positions",
|
|
11018
|
+
positionsCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
|
|
11019
|
+
" (",
|
|
11020
|
+
positionsCount,
|
|
11021
|
+
")"
|
|
11022
|
+
] })
|
|
11023
|
+
] }),
|
|
11024
|
+
/* @__PURE__ */ jsxs(Tab, { $active: activeTab === "subscriptions", onClick: () => handleTabChange("subscriptions"), children: [
|
|
11025
|
+
"Initial Offerings",
|
|
11026
|
+
pendingOfferingsCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
|
|
11027
|
+
" (",
|
|
11028
|
+
pendingOfferingsCount,
|
|
11029
|
+
")"
|
|
11030
|
+
] })
|
|
11031
|
+
] }),
|
|
11032
|
+
/* @__PURE__ */ jsxs(Tab, { $active: activeTab === "open-orders", onClick: () => handleTabChange("open-orders"), children: [
|
|
11033
|
+
"Open Orders",
|
|
11034
|
+
openOrdersCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
|
|
11035
|
+
" (",
|
|
11036
|
+
openOrdersCount,
|
|
11037
|
+
")"
|
|
11038
|
+
] })
|
|
11039
|
+
] }),
|
|
11040
|
+
/* @__PURE__ */ jsxs(Tab, { $active: activeTab === "orders", onClick: () => handleTabChange("orders"), children: [
|
|
11041
|
+
"Order History",
|
|
11042
|
+
pendingHistoryCount > 0 && /* @__PURE__ */ jsxs(TabCount, { children: [
|
|
11043
|
+
" (",
|
|
11044
|
+
pendingHistoryCount,
|
|
11045
|
+
")"
|
|
11046
|
+
] })
|
|
11047
|
+
] }),
|
|
10688
11048
|
/* @__PURE__ */ jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
|
|
10689
11049
|
/* @__PURE__ */ jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
|
|
10690
11050
|
] }),
|
|
@@ -10769,8 +11129,10 @@ function PortfolioActivityPanel({
|
|
|
10769
11129
|
openOrders.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
|
|
10770
11130
|
pageSlice(openOrders).map((order) => {
|
|
10771
11131
|
const meta = getOrderStatusMeta(order.status);
|
|
10772
|
-
const
|
|
10773
|
-
const
|
|
11132
|
+
const isMarket = order.type === "MARKET";
|
|
11133
|
+
const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
|
|
11134
|
+
const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
|
|
11135
|
+
const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
|
|
10774
11136
|
const isCancelling = cancellingOrderId === order.id;
|
|
10775
11137
|
return /* @__PURE__ */ jsxs(ActivityRow, { children: [
|
|
10776
11138
|
/* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
@@ -10780,9 +11142,10 @@ function PortfolioActivityPanel({
|
|
|
10780
11142
|
formatNumber2(order.quantity),
|
|
10781
11143
|
" tokens \xB7 ",
|
|
10782
11144
|
prettyLabel(order.type),
|
|
11145
|
+
priceSegment,
|
|
10783
11146
|
" \xB7 ",
|
|
10784
|
-
|
|
10785
|
-
" \xB7 ",
|
|
11147
|
+
filledPercent,
|
|
11148
|
+
"% filled \xB7 ",
|
|
10786
11149
|
formatTimestamp(order.createdAt)
|
|
10787
11150
|
] })
|
|
10788
11151
|
] }),
|
|
@@ -10809,8 +11172,10 @@ function PortfolioActivityPanel({
|
|
|
10809
11172
|
orderHistory.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
|
|
10810
11173
|
pageSlice(orderHistory).map((order) => {
|
|
10811
11174
|
const meta = getOrderStatusMeta(order.status);
|
|
10812
|
-
const
|
|
10813
|
-
const
|
|
11175
|
+
const isMarket = order.type === "MARKET";
|
|
11176
|
+
const priceSegment = isMarket || !order.price ? "" : ` \xB7 ${formatCurrency5(order.price)}`;
|
|
11177
|
+
const filledPercent = order.quantity > 0 ? Math.round(order.filledQuantity / order.quantity * 100) : 0;
|
|
11178
|
+
const amountDisplay = !isMarket && order.price ? formatCurrency5(order.price * order.quantity) : "\u2014";
|
|
10814
11179
|
return /* @__PURE__ */ jsxs(ActivityRow, { children: [
|
|
10815
11180
|
/* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
10816
11181
|
/* @__PURE__ */ jsxs(ActivityInfo, { children: [
|
|
@@ -10819,9 +11184,10 @@ function PortfolioActivityPanel({
|
|
|
10819
11184
|
formatNumber2(order.quantity),
|
|
10820
11185
|
" tokens \xB7 ",
|
|
10821
11186
|
prettyLabel(order.type),
|
|
11187
|
+
priceSegment,
|
|
10822
11188
|
" \xB7 ",
|
|
10823
|
-
|
|
10824
|
-
" \xB7 ",
|
|
11189
|
+
filledPercent,
|
|
11190
|
+
"% filled \xB7 ",
|
|
10825
11191
|
formatTimestamp(order.createdAt)
|
|
10826
11192
|
] })
|
|
10827
11193
|
] }),
|
|
@@ -10963,6 +11329,12 @@ var Tab = styled24.button`
|
|
|
10963
11329
|
color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
|
|
10964
11330
|
}
|
|
10965
11331
|
`;
|
|
11332
|
+
var TabCount = styled24.span`
|
|
11333
|
+
color: inherit;
|
|
11334
|
+
opacity: 0.7;
|
|
11335
|
+
font-weight: 500;
|
|
11336
|
+
margin-left: 2px;
|
|
11337
|
+
`;
|
|
10966
11338
|
var ActivityRow = styled24.div`
|
|
10967
11339
|
display: grid;
|
|
10968
11340
|
grid-template-columns: auto 1fr auto auto;
|
|
@@ -11606,6 +11978,7 @@ function PropertyBuy({
|
|
|
11606
11978
|
recentOrders = [],
|
|
11607
11979
|
ordersAllocated = 0,
|
|
11608
11980
|
subscribers = 0,
|
|
11981
|
+
isLoadingActivity = false,
|
|
11609
11982
|
selectorItems,
|
|
11610
11983
|
onSelectorSelect,
|
|
11611
11984
|
portfolioActivity
|
|
@@ -11638,6 +12011,7 @@ function PropertyBuy({
|
|
|
11638
12011
|
const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
|
|
11639
12012
|
const ipoStatus = saleData?.status ?? "PENDING";
|
|
11640
12013
|
const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
|
|
12014
|
+
const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
|
|
11641
12015
|
const statusLabel = ipoStatus;
|
|
11642
12016
|
const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
|
|
11643
12017
|
const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
|
|
@@ -11788,6 +12162,8 @@ function PropertyBuy({
|
|
|
11788
12162
|
VideoActivitySection,
|
|
11789
12163
|
{
|
|
11790
12164
|
ipoStarted,
|
|
12165
|
+
ipoEnded,
|
|
12166
|
+
isLoading: isLoadingActivity,
|
|
11791
12167
|
recentOrders,
|
|
11792
12168
|
ordersAllocated,
|
|
11793
12169
|
tokenPrice
|
|
@@ -14399,7 +14775,68 @@ function useToast() {
|
|
|
14399
14775
|
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
14400
14776
|
return ctx;
|
|
14401
14777
|
}
|
|
14778
|
+
var INTERVALS = [1e3, 2e3, 4e3, 5e3, 7e3, 1e4, 12e3];
|
|
14779
|
+
function useAdaptivePolling({ enabled, onPoll }) {
|
|
14780
|
+
const onPollRef = useRef(onPoll);
|
|
14781
|
+
onPollRef.current = onPoll;
|
|
14782
|
+
useEffect(() => {
|
|
14783
|
+
if (!enabled) return;
|
|
14784
|
+
let cancelled = false;
|
|
14785
|
+
let timeoutId = null;
|
|
14786
|
+
let step = 0;
|
|
14787
|
+
const clear = () => {
|
|
14788
|
+
if (timeoutId) {
|
|
14789
|
+
clearTimeout(timeoutId);
|
|
14790
|
+
timeoutId = null;
|
|
14791
|
+
}
|
|
14792
|
+
};
|
|
14793
|
+
const isHidden = () => typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
14794
|
+
const tick = async () => {
|
|
14795
|
+
if (cancelled) return;
|
|
14796
|
+
if (isHidden()) {
|
|
14797
|
+
return;
|
|
14798
|
+
}
|
|
14799
|
+
try {
|
|
14800
|
+
await onPollRef.current();
|
|
14801
|
+
} catch {
|
|
14802
|
+
}
|
|
14803
|
+
if (cancelled) return;
|
|
14804
|
+
step = Math.min(step + 1, INTERVALS.length - 1);
|
|
14805
|
+
timeoutId = setTimeout(tick, INTERVALS[step]);
|
|
14806
|
+
};
|
|
14807
|
+
const onVisibility = () => {
|
|
14808
|
+
if (document.visibilityState === "visible") {
|
|
14809
|
+
step = 0;
|
|
14810
|
+
clear();
|
|
14811
|
+
timeoutId = setTimeout(tick, 0);
|
|
14812
|
+
}
|
|
14813
|
+
};
|
|
14814
|
+
if (typeof document !== "undefined") {
|
|
14815
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
14816
|
+
}
|
|
14817
|
+
timeoutId = setTimeout(tick, INTERVALS[0]);
|
|
14818
|
+
return () => {
|
|
14819
|
+
cancelled = true;
|
|
14820
|
+
clear();
|
|
14821
|
+
if (typeof document !== "undefined") {
|
|
14822
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
14823
|
+
}
|
|
14824
|
+
};
|
|
14825
|
+
}, [enabled]);
|
|
14826
|
+
}
|
|
14827
|
+
function hasPendingActivity(data) {
|
|
14828
|
+
if (!data) return false;
|
|
14829
|
+
const openPending = data.openOrders?.some((o) => {
|
|
14830
|
+
const s = o.status.toUpperCase();
|
|
14831
|
+
return s === "OPEN" || s === "PARTIALLY_FILLED";
|
|
14832
|
+
}) ?? false;
|
|
14833
|
+
if (openPending) return true;
|
|
14834
|
+
return data.offeringOrders?.some((o) => {
|
|
14835
|
+
const s = o.status.toUpperCase();
|
|
14836
|
+
return s !== "FILLED" && s !== "ALLOCATED" && s !== "CONFIRMED" && s !== "CANCELLED" && s !== "CANCELED" && s !== "REJECTED";
|
|
14837
|
+
}) ?? false;
|
|
14838
|
+
}
|
|
14402
14839
|
|
|
14403
|
-
export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants, useToast };
|
|
14840
|
+
export { AssetSelectorBar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Header, HousePositionSlider, HousePositionSliderMobile, LoafLiquidityBadge, LoafLiquidityLogo, LoginPopup, MobileTradeNav, Orderbook, owner_booking_default as OwnerBooking, PaymentPopup, PortfolioActivityPanel, PortfolioSummary, PriceChart, PropertyBuy, PropertyCompareBar, PropertyDocuments, PropertyHeroHeader, PropertyHistory, PropertyInspectionTimes, PropertyNewsUpdates, PropertyOffers, PropertyOverview, PropertyPhotoGallery, PropertySubheader, PropertyTour, PropertyValuation, Skeleton, ToastProvider, TradeConfirmationModal, TradingSlider, YourOrders, badgeVariants, buttonVariants, hasPendingActivity, useAdaptivePolling, useToast };
|
|
14404
14841
|
//# sourceMappingURL=index.mjs.map
|
|
14405
14842
|
//# sourceMappingURL=index.mjs.map
|