@loafmarkets/ui 0.1.41 → 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 +804 -353
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +687 -239
- 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
|
}, []);
|
|
@@ -4852,7 +5115,7 @@ var Header = ({
|
|
|
4852
5115
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4853
5116
|
/* @__PURE__ */ jsx(SafeAreaCover, {}),
|
|
4854
5117
|
/* @__PURE__ */ jsx(Overlay, { $isOpen: isMobileMenuOpen, onClick: () => setIsMobileMenuOpen(false) }),
|
|
4855
|
-
/* @__PURE__ */ jsxs(HeaderContainer, { children: [
|
|
5118
|
+
/* @__PURE__ */ jsxs(HeaderContainer, { id: "loaf-header", children: [
|
|
4856
5119
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [
|
|
4857
5120
|
/* @__PURE__ */ jsxs(Logo, { children: [
|
|
4858
5121
|
/* @__PURE__ */ jsx(LogoLink, { href: logoHref ?? resolvedHomePath, onClick: handleLogoNavigation, children: /* @__PURE__ */ jsx("img", { src: Loaf_logo_Banner_default, alt: "LOAF Logo" }) }),
|
|
@@ -5090,6 +5353,7 @@ var Header = ({
|
|
|
5090
5353
|
)
|
|
5091
5354
|
] })
|
|
5092
5355
|
] }),
|
|
5356
|
+
/* @__PURE__ */ jsx(HeaderSpacer, {}),
|
|
5093
5357
|
LoginPopupComponent && showLoginPopup && /* @__PURE__ */ jsx(
|
|
5094
5358
|
LoginPopupComponent,
|
|
5095
5359
|
{
|
|
@@ -5105,8 +5369,8 @@ var SafeAreaCover = styled24.div`
|
|
|
5105
5369
|
top: 0;
|
|
5106
5370
|
left: 0;
|
|
5107
5371
|
right: 0;
|
|
5108
|
-
height: env(safe-area-inset-top, 0px);
|
|
5109
|
-
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));
|
|
5110
5374
|
background-color: #0d1117;
|
|
5111
5375
|
z-index: 1001;
|
|
5112
5376
|
pointer-events: none;
|
|
@@ -5160,23 +5424,31 @@ var HeaderContainer = styled24.header`
|
|
|
5160
5424
|
/* Split padding so browsers that don't support env() inside shorthand
|
|
5161
5425
|
still get the horizontal padding — only the top falls back to 0 */
|
|
5162
5426
|
padding: 0 2rem;
|
|
5163
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5427
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5164
5428
|
background-color: #0d1117;
|
|
5165
5429
|
border-bottom: 1px solid #232a32;
|
|
5166
|
-
position:
|
|
5430
|
+
position: fixed;
|
|
5167
5431
|
top: 0;
|
|
5432
|
+
left: 0;
|
|
5433
|
+
right: 0;
|
|
5168
5434
|
z-index: 1000;
|
|
5169
5435
|
width: 100%;
|
|
5170
5436
|
/* Fallback min-height for browsers that can't evaluate calc+env */
|
|
5171
5437
|
min-height: 56px;
|
|
5172
|
-
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)));
|
|
5173
5439
|
box-sizing: border-box;
|
|
5174
5440
|
|
|
5175
5441
|
@media (max-width: 768px) {
|
|
5176
5442
|
padding: 0 1rem;
|
|
5177
|
-
padding-top: env(safe-area-inset-top, 0px);
|
|
5443
|
+
padding-top: max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px));
|
|
5178
5444
|
}
|
|
5179
5445
|
`;
|
|
5446
|
+
var HeaderSpacer = styled24.div`
|
|
5447
|
+
width: 100%;
|
|
5448
|
+
min-height: 56px;
|
|
5449
|
+
min-height: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5450
|
+
flex-shrink: 0;
|
|
5451
|
+
`;
|
|
5180
5452
|
var Logo = styled24.div`
|
|
5181
5453
|
display: flex;
|
|
5182
5454
|
align-items: center;
|
|
@@ -5229,10 +5501,12 @@ var Nav = styled24.nav`
|
|
|
5229
5501
|
@media (max-width: 1300px) {
|
|
5230
5502
|
position: fixed;
|
|
5231
5503
|
top: 56px;
|
|
5504
|
+
top: calc(56px + max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5232
5505
|
right: ${(props) => props.$isOpen ? "0" : "-100%"} ;
|
|
5233
5506
|
width: 280px;
|
|
5234
5507
|
max-width: 280px;
|
|
5235
5508
|
height: calc(100vh - 56px);
|
|
5509
|
+
height: calc(100vh - 56px - max(env(safe-area-inset-top, 0px), var(--telegram-safe-top, 0px)));
|
|
5236
5510
|
background: linear-gradient(180deg, #0f1419 0%, #0a0e13 100%);
|
|
5237
5511
|
z-index: 1000;
|
|
5238
5512
|
transition: right 0.3s ease;
|
|
@@ -5505,10 +5779,10 @@ var MobileNavItem = styled24.div`
|
|
|
5505
5779
|
padding-left: 24px;
|
|
5506
5780
|
}
|
|
5507
5781
|
`;
|
|
5508
|
-
var PropertySubheader =
|
|
5782
|
+
var PropertySubheader = React9.forwardRef(
|
|
5509
5783
|
({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
|
|
5510
|
-
const tabsContainerRef =
|
|
5511
|
-
|
|
5784
|
+
const tabsContainerRef = React9.useRef(null);
|
|
5785
|
+
React9.useEffect(() => {
|
|
5512
5786
|
const container = tabsContainerRef.current;
|
|
5513
5787
|
if (!container) return;
|
|
5514
5788
|
const isMobile = window.innerWidth <= 768;
|
|
@@ -5664,7 +5938,7 @@ var LoginPopup = ({
|
|
|
5664
5938
|
const [fiatFundingLoading, setFiatFundingLoading] = useState(false);
|
|
5665
5939
|
const [fundingError, setFundingError] = useState("");
|
|
5666
5940
|
const [transakWidgetUrl, setTransakWidgetUrl] = useState(null);
|
|
5667
|
-
const suppressAutoCloseRef =
|
|
5941
|
+
const suppressAutoCloseRef = React9__default.useRef(false);
|
|
5668
5942
|
useEffect(() => {
|
|
5669
5943
|
if (typeof initialView === "string") {
|
|
5670
5944
|
setView(initialView);
|
|
@@ -6844,7 +7118,7 @@ var MiniLiveFeed = () => {
|
|
|
6844
7118
|
);
|
|
6845
7119
|
};
|
|
6846
7120
|
LoginPopup.displayName = "LoginPopup";
|
|
6847
|
-
var PropertyCompareBar =
|
|
7121
|
+
var PropertyCompareBar = React9.forwardRef(
|
|
6848
7122
|
({
|
|
6849
7123
|
className,
|
|
6850
7124
|
addresses,
|
|
@@ -6855,7 +7129,7 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6855
7129
|
price,
|
|
6856
7130
|
...props
|
|
6857
7131
|
}, ref) => {
|
|
6858
|
-
const normalizedAddresses =
|
|
7132
|
+
const normalizedAddresses = React9.useMemo(() => {
|
|
6859
7133
|
return addresses.map(
|
|
6860
7134
|
(option) => typeof option === "string" ? { id: option, label: option } : option
|
|
6861
7135
|
);
|
|
@@ -6863,11 +7137,11 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6863
7137
|
const hasAddresses = normalizedAddresses.length > 0;
|
|
6864
7138
|
const firstAddressId = normalizedAddresses[0]?.id;
|
|
6865
7139
|
const isControlled = selectedAddressId !== void 0;
|
|
6866
|
-
const [internalSelectedId, setInternalSelectedId] =
|
|
7140
|
+
const [internalSelectedId, setInternalSelectedId] = React9.useState(
|
|
6867
7141
|
() => isControlled ? void 0 : firstAddressId
|
|
6868
7142
|
);
|
|
6869
7143
|
const resolvedSelectedId = isControlled ? selectedAddressId : internalSelectedId;
|
|
6870
|
-
|
|
7144
|
+
React9.useEffect(() => {
|
|
6871
7145
|
if (!isControlled) {
|
|
6872
7146
|
setInternalSelectedId((current) => {
|
|
6873
7147
|
if (current != null && normalizedAddresses.some((option) => option.id === current)) {
|
|
@@ -6878,9 +7152,9 @@ var PropertyCompareBar = React5.forwardRef(
|
|
|
6878
7152
|
}
|
|
6879
7153
|
}, [firstAddressId, isControlled, normalizedAddresses]);
|
|
6880
7154
|
const selectedOption = normalizedAddresses.find((option) => option.id === resolvedSelectedId) ?? normalizedAddresses[0];
|
|
6881
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
6882
|
-
const dropdownRef =
|
|
6883
|
-
|
|
7155
|
+
const [isDropdownOpen, setIsDropdownOpen] = React9.useState(false);
|
|
7156
|
+
const dropdownRef = React9.useRef(null);
|
|
7157
|
+
React9.useEffect(() => {
|
|
6884
7158
|
if (!isDropdownOpen) return;
|
|
6885
7159
|
const handleClick = (event) => {
|
|
6886
7160
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -7603,7 +7877,8 @@ function PropertyOverview({
|
|
|
7603
7877
|
bathrooms,
|
|
7604
7878
|
carSpaces,
|
|
7605
7879
|
propertyTypeLabel,
|
|
7606
|
-
tokensIssued: tokensIssuedProp
|
|
7880
|
+
tokensIssued: tokensIssuedProp,
|
|
7881
|
+
isLoading = false
|
|
7607
7882
|
}) {
|
|
7608
7883
|
const [isDescExpanded, setDescExpanded] = useState(false);
|
|
7609
7884
|
const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
|
|
@@ -7641,13 +7916,14 @@ function PropertyOverview({
|
|
|
7641
7916
|
const weeklyRent = overviewData?.weeklyRent ?? 0;
|
|
7642
7917
|
const annualRent = weeklyRent * 52;
|
|
7643
7918
|
const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
|
|
7919
|
+
const loadingSkeleton = /* @__PURE__ */ jsx(Skeleton, { width: 90, height: 18 });
|
|
7644
7920
|
const financialItems = financialItemsProp ?? [
|
|
7645
|
-
{ label: "Token Price", value: tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "N/A", gold: true },
|
|
7646
|
-
{ label: "Property Value", value: resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "N/A" },
|
|
7647
|
-
{ label: "Weekly Rent", value: weeklyRent > 0 ? `$${weeklyRent.toLocaleString()}/wk` : "N/A", badge: weeklyRent > 0 ? "Rented" : void 0 },
|
|
7648
|
-
{ label: "Dividend Yield", value: dividendYield ? `${dividendYield}%` : "N/A" },
|
|
7649
|
-
{ label: "Total Tokens", value: resolvedTokensIssued ? resolvedTokensIssued.toLocaleString() : "N/A" },
|
|
7650
|
-
{ 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" }
|
|
7651
7927
|
];
|
|
7652
7928
|
const galleryImages = images ?? [];
|
|
7653
7929
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -9491,6 +9767,8 @@ var formatTimeAgo2 = (timestamp) => {
|
|
|
9491
9767
|
};
|
|
9492
9768
|
function VideoActivitySection({
|
|
9493
9769
|
ipoStarted,
|
|
9770
|
+
ipoEnded = false,
|
|
9771
|
+
isLoading = false,
|
|
9494
9772
|
recentOrders = [],
|
|
9495
9773
|
ordersAllocated = 0,
|
|
9496
9774
|
tokenPrice = 0
|
|
@@ -9499,6 +9777,9 @@ function VideoActivitySection({
|
|
|
9499
9777
|
() => [...recentOrders].sort((a, b) => b.timestamp - a.timestamp).slice(0, 7),
|
|
9500
9778
|
[recentOrders]
|
|
9501
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);
|
|
9502
9783
|
return /* @__PURE__ */ jsxs(Section3, { children: [
|
|
9503
9784
|
/* @__PURE__ */ jsxs(VideoPanel, { children: [
|
|
9504
9785
|
/* @__PURE__ */ jsx("div", { className: "section-header", children: /* @__PURE__ */ jsx("h3", { children: "Musgrave" }) }),
|
|
@@ -9510,31 +9791,40 @@ function VideoActivitySection({
|
|
|
9510
9791
|
/* @__PURE__ */ jsxs(ActivityPanel, { children: [
|
|
9511
9792
|
/* @__PURE__ */ jsxs("div", { className: "section-header", children: [
|
|
9512
9793
|
/* @__PURE__ */ jsxs("h3", { children: [
|
|
9513
|
-
/* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted }),
|
|
9794
|
+
/* @__PURE__ */ jsx(LiveIndicatorDot, { $active: ipoStarted && !ipoEnded }),
|
|
9514
9795
|
"Recent Order Activity"
|
|
9515
9796
|
] }),
|
|
9516
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
9797
|
+
/* @__PURE__ */ jsx("span", { children: headerStatusText })
|
|
9517
9798
|
] }),
|
|
9518
|
-
/* @__PURE__ */ jsx("div", { className: "activity-content", children:
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
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: [
|
|
9538
9828
|
/* @__PURE__ */ jsx("div", { className: "spinner" }),
|
|
9539
9829
|
/* @__PURE__ */ jsx("p", { children: "Activity will appear once the Offering opens" })
|
|
9540
9830
|
] }) })
|
|
@@ -9675,6 +9965,43 @@ var ActivityPanel = styled24.div`
|
|
|
9675
9965
|
to { transform: rotate(360deg); }
|
|
9676
9966
|
}
|
|
9677
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
|
+
`;
|
|
9678
10005
|
var FeedList = styled24.div`
|
|
9679
10006
|
width: 100%;
|
|
9680
10007
|
overflow-y: auto;
|
|
@@ -10661,6 +10988,22 @@ function PortfolioActivityPanel({
|
|
|
10661
10988
|
return 0;
|
|
10662
10989
|
}
|
|
10663
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
|
+
);
|
|
10664
11007
|
const activityTotalPages = Math.ceil(activeTabTotal / pageSize);
|
|
10665
11008
|
const pageSlice = (arr) => arr.slice(activityPage * pageSize, (activityPage + 1) * pageSize);
|
|
10666
11009
|
const handleTabChange = (tab) => {
|
|
@@ -10670,10 +11013,38 @@ function PortfolioActivityPanel({
|
|
|
10670
11013
|
return /* @__PURE__ */ jsxs(Container2, { className, style, children: [
|
|
10671
11014
|
/* @__PURE__ */ jsx(PanelTitle, { children: "Activity" }),
|
|
10672
11015
|
/* @__PURE__ */ jsxs(TabContainer, { children: [
|
|
10673
|
-
showPositionsTab && /* @__PURE__ */
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
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
|
+
] }),
|
|
10677
11048
|
/* @__PURE__ */ jsx(Tab, { $active: activeTab === "trades", onClick: () => handleTabChange("trades"), children: "Trade History" }),
|
|
10678
11049
|
/* @__PURE__ */ jsx(Tab, { $active: activeTab === "transfers", onClick: () => handleTabChange("transfers"), children: "Transfers" })
|
|
10679
11050
|
] }),
|
|
@@ -10758,8 +11129,10 @@ function PortfolioActivityPanel({
|
|
|
10758
11129
|
openOrders.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "Open orders will appear here while they are working in the market." }),
|
|
10759
11130
|
pageSlice(openOrders).map((order) => {
|
|
10760
11131
|
const meta = getOrderStatusMeta(order.status);
|
|
10761
|
-
const
|
|
10762
|
-
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";
|
|
10763
11136
|
const isCancelling = cancellingOrderId === order.id;
|
|
10764
11137
|
return /* @__PURE__ */ jsxs(ActivityRow, { children: [
|
|
10765
11138
|
/* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
@@ -10769,9 +11142,10 @@ function PortfolioActivityPanel({
|
|
|
10769
11142
|
formatNumber2(order.quantity),
|
|
10770
11143
|
" tokens \xB7 ",
|
|
10771
11144
|
prettyLabel(order.type),
|
|
11145
|
+
priceSegment,
|
|
10772
11146
|
" \xB7 ",
|
|
10773
|
-
|
|
10774
|
-
" \xB7 ",
|
|
11147
|
+
filledPercent,
|
|
11148
|
+
"% filled \xB7 ",
|
|
10775
11149
|
formatTimestamp(order.createdAt)
|
|
10776
11150
|
] })
|
|
10777
11151
|
] }),
|
|
@@ -10798,8 +11172,10 @@ function PortfolioActivityPanel({
|
|
|
10798
11172
|
orderHistory.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "No orders yet. Place a trade to see it appear here." }),
|
|
10799
11173
|
pageSlice(orderHistory).map((order) => {
|
|
10800
11174
|
const meta = getOrderStatusMeta(order.status);
|
|
10801
|
-
const
|
|
10802
|
-
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";
|
|
10803
11179
|
return /* @__PURE__ */ jsxs(ActivityRow, { children: [
|
|
10804
11180
|
/* @__PURE__ */ jsx(ActivitySideBadge, { $side: sideLabel(order.side), children: sideLabel(order.side) }),
|
|
10805
11181
|
/* @__PURE__ */ jsxs(ActivityInfo, { children: [
|
|
@@ -10808,9 +11184,10 @@ function PortfolioActivityPanel({
|
|
|
10808
11184
|
formatNumber2(order.quantity),
|
|
10809
11185
|
" tokens \xB7 ",
|
|
10810
11186
|
prettyLabel(order.type),
|
|
11187
|
+
priceSegment,
|
|
10811
11188
|
" \xB7 ",
|
|
10812
|
-
|
|
10813
|
-
" \xB7 ",
|
|
11189
|
+
filledPercent,
|
|
11190
|
+
"% filled \xB7 ",
|
|
10814
11191
|
formatTimestamp(order.createdAt)
|
|
10815
11192
|
] })
|
|
10816
11193
|
] }),
|
|
@@ -10952,6 +11329,12 @@ var Tab = styled24.button`
|
|
|
10952
11329
|
color: ${({ $active }) => $active ? "#fff" : "rgba(255, 255, 255, 0.65)"};
|
|
10953
11330
|
}
|
|
10954
11331
|
`;
|
|
11332
|
+
var TabCount = styled24.span`
|
|
11333
|
+
color: inherit;
|
|
11334
|
+
opacity: 0.7;
|
|
11335
|
+
font-weight: 500;
|
|
11336
|
+
margin-left: 2px;
|
|
11337
|
+
`;
|
|
10955
11338
|
var ActivityRow = styled24.div`
|
|
10956
11339
|
display: grid;
|
|
10957
11340
|
grid-template-columns: auto 1fr auto auto;
|
|
@@ -11595,6 +11978,7 @@ function PropertyBuy({
|
|
|
11595
11978
|
recentOrders = [],
|
|
11596
11979
|
ordersAllocated = 0,
|
|
11597
11980
|
subscribers = 0,
|
|
11981
|
+
isLoadingActivity = false,
|
|
11598
11982
|
selectorItems,
|
|
11599
11983
|
onSelectorSelect,
|
|
11600
11984
|
portfolioActivity
|
|
@@ -11627,6 +12011,7 @@ function PropertyBuy({
|
|
|
11627
12011
|
const offeringValuation = saleData?.offeringValuation ?? tokenPrice * supplyToSell;
|
|
11628
12012
|
const ipoStatus = saleData?.status ?? "PENDING";
|
|
11629
12013
|
const ipoStarted = ipoStatus === "LIVE" || isPrivateClient && ipoStatus === "PENDING";
|
|
12014
|
+
const ipoEnded = ipoStatus === "CLOSED" || ipoStatus === "CANCELLED";
|
|
11630
12015
|
const statusLabel = ipoStatus;
|
|
11631
12016
|
const statusColor = STATUS_COLOR2[ipoStatus] ?? "#D4AF37";
|
|
11632
12017
|
const displayStatusLabel = isPrivateClient && ipoStatus !== "LIVE" ? "Private Client Access" : statusLabel;
|
|
@@ -11777,6 +12162,8 @@ function PropertyBuy({
|
|
|
11777
12162
|
VideoActivitySection,
|
|
11778
12163
|
{
|
|
11779
12164
|
ipoStarted,
|
|
12165
|
+
ipoEnded,
|
|
12166
|
+
isLoading: isLoadingActivity,
|
|
11780
12167
|
recentOrders,
|
|
11781
12168
|
ordersAllocated,
|
|
11782
12169
|
tokenPrice
|
|
@@ -14388,7 +14775,68 @@ function useToast() {
|
|
|
14388
14775
|
if (!ctx) throw new Error("useToast must be used within a ToastProvider");
|
|
14389
14776
|
return ctx;
|
|
14390
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
|
+
}
|
|
14391
14839
|
|
|
14392
|
-
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 };
|
|
14393
14841
|
//# sourceMappingURL=index.mjs.map
|
|
14394
14842
|
//# sourceMappingURL=index.mjs.map
|