@loafmarkets/ui 0.0.1

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.mjs ADDED
@@ -0,0 +1,1660 @@
1
+ import * as React5 from 'react';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva } from 'class-variance-authority';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { CalendarDays, ArrowUpRight, Newspaper, BedDouble, Bath, CarFront, Building2, Sparkles, LineChart } from 'lucide-react';
8
+ import { createChart } from 'lightweight-charts';
9
+
10
+ // src/components/button.tsx
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+ var buttonVariants = cva(
15
+ "inline-flex items-center justify-center font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
16
+ {
17
+ variants: {
18
+ variant: {
19
+ primary: "bg-teal-500 text-slate-950 hover:bg-teal-400 focus-visible:ring-teal-200",
20
+ accent: "bg-[var(--color-accent,#e6c87e)] text-black hover:bg-[var(--color-accent-hover,#f8d12f)] focus-visible:ring-[var(--color-accent,#e6c87e)]",
21
+ accentOutline: "border border-[var(--color-accent,#e6c87e)] bg-transparent text-[var(--color-accent,#e6c87e)] hover:bg-[rgba(230,200,126,0.10)] focus-visible:ring-[var(--color-accent,#e6c87e)]",
22
+ media: "border border-white/10 bg-transparent text-white/90 hover:bg-white/5 hover:border-[var(--color-accent,#e6c87e)] hover:text-[var(--color-accent,#e6c87e)] focus-visible:ring-[var(--color-accent,#e6c87e)]",
23
+ outline: "border border-slate-800/20 bg-white text-slate-900 hover:border-slate-800/40 focus-visible:ring-slate-200",
24
+ ghost: "bg-transparent text-slate-900 hover:bg-slate-900/5 focus-visible:ring-slate-200",
25
+ danger: "bg-rose-500 text-white hover:bg-rose-400 focus-visible:ring-rose-200"
26
+ },
27
+ size: {
28
+ sm: "h-9 px-4 text-sm",
29
+ md: "h-11 px-6 text-base",
30
+ lg: "h-12 px-7 text-lg",
31
+ icon: "h-10 w-10"
32
+ },
33
+ radius: {
34
+ pill: "rounded-full",
35
+ md: "rounded"
36
+ }
37
+ },
38
+ defaultVariants: {
39
+ variant: "primary",
40
+ size: "md",
41
+ radius: "pill"
42
+ }
43
+ }
44
+ );
45
+ var Button = React5.forwardRef(
46
+ ({ className, variant, size, radius, asChild = false, ...props }, ref) => {
47
+ const Comp = asChild ? Slot : "button";
48
+ return /* @__PURE__ */ jsx(
49
+ Comp,
50
+ {
51
+ ref,
52
+ className: cn(buttonVariants({ variant, size, radius }), className),
53
+ ...props
54
+ }
55
+ );
56
+ }
57
+ );
58
+ Button.displayName = "Button";
59
+ var badgeVariants = cva(
60
+ "inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold uppercase tracking-wide transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
61
+ {
62
+ variants: {
63
+ variant: {
64
+ default: "border-transparent bg-slate-900 text-white focus-visible:ring-slate-300",
65
+ muted: "border-transparent bg-slate-100 text-slate-600 focus-visible:ring-slate-200",
66
+ outline: "border-slate-200 bg-white text-slate-600 focus-visible:ring-slate-200",
67
+ success: "border-transparent bg-teal-500/15 text-teal-600 focus-visible:ring-teal-200",
68
+ active: "border-transparent bg-[rgba(14,203,129,0.25)] text-[#0ecb81] focus-visible:ring-[rgba(14,203,129,0.35)]",
69
+ pending: "border-transparent bg-white/10 text-white/60 focus-visible:ring-white/20",
70
+ rejected: "border-transparent bg-[rgba(246,70,93,0.20)] text-[#f6465d] focus-visible:ring-[rgba(246,70,93,0.30)]"
71
+ },
72
+ size: {
73
+ sm: "px-2.5 py-0.5 text-[11px]",
74
+ md: "px-3 py-1 text-xs"
75
+ }
76
+ },
77
+ defaultVariants: {
78
+ variant: "default",
79
+ size: "md"
80
+ }
81
+ }
82
+ );
83
+ var Badge = React5.forwardRef(
84
+ ({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, className: cn(badgeVariants({ variant, size }), className), ...props })
85
+ );
86
+ Badge.displayName = "Badge";
87
+ var Card = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
88
+ "div",
89
+ {
90
+ ref,
91
+ className: cn(
92
+ "rounded-3xl border border-slate-200 bg-white shadow-sm transition hover:shadow-md",
93
+ className
94
+ ),
95
+ ...props
96
+ }
97
+ ));
98
+ Card.displayName = "Card";
99
+ var CardHeader = React5.forwardRef(
100
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
101
+ );
102
+ CardHeader.displayName = "CardHeader";
103
+ var CardTitle = React5.forwardRef(
104
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
105
+ "h3",
106
+ {
107
+ ref,
108
+ className: cn("text-xl font-semibold tracking-tight text-slate-900", className),
109
+ ...props
110
+ }
111
+ )
112
+ );
113
+ CardTitle.displayName = "CardTitle";
114
+ var CardDescription = React5.forwardRef(
115
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-slate-500", className), ...props })
116
+ );
117
+ CardDescription.displayName = "CardDescription";
118
+ var CardContent = React5.forwardRef(
119
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("px-6 pb-6 pt-2 text-sm text-slate-600", className), ...props })
120
+ );
121
+ CardContent.displayName = "CardContent";
122
+ var CardFooter = React5.forwardRef(
123
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center border-t border-slate-100 px-6 py-4", className), ...props })
124
+ );
125
+ CardFooter.displayName = "CardFooter";
126
+ var defaultFormatCurrency = (value) => new Intl.NumberFormat("en-US", {
127
+ style: "currency",
128
+ currency: "USD",
129
+ minimumFractionDigits: 2,
130
+ maximumFractionDigits: 2
131
+ }).format(value);
132
+ var defaultFormatPercent = (value) => {
133
+ const sign = value >= 0 ? "+" : "-";
134
+ return `${sign}${Math.abs(value).toFixed(2)}%`;
135
+ };
136
+ var defaultFormatSignedCurrency = (value) => {
137
+ const sign = value >= 0 ? "+" : "-";
138
+ return `${sign}${defaultFormatCurrency(Math.abs(value))}`;
139
+ };
140
+ var PortfolioSummary = React5.forwardRef(
141
+ ({
142
+ availableCash,
143
+ portfolioValue,
144
+ totalReturnPercent,
145
+ unrealizedPnl,
146
+ onResetAccount,
147
+ positionsHeading = "Current Positions",
148
+ emptyPositionsText = "No positions yet. Start trading to build your portfolio!",
149
+ formatCurrency = defaultFormatCurrency,
150
+ formatPercent = defaultFormatPercent,
151
+ formatSignedCurrency = defaultFormatSignedCurrency,
152
+ className,
153
+ children,
154
+ ...props
155
+ }, ref) => {
156
+ const totalReturnClassName = totalReturnPercent >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
157
+ const pnlClassName = unrealizedPnl >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
158
+ return /* @__PURE__ */ jsxs(
159
+ Card,
160
+ {
161
+ ref,
162
+ className: cn(
163
+ "w-full max-w-[560px] rounded-[12px] border border-white/10 bg-black/30 p-6 text-white backdrop-blur-md",
164
+ className
165
+ ),
166
+ ...props,
167
+ children: [
168
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
169
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
170
+ /* @__PURE__ */ jsx(CardTitle, { className: "m-0 text-[1.1rem] font-semibold text-white", children: "Portfolio Summary" }),
171
+ onResetAccount ? /* @__PURE__ */ jsx(
172
+ "button",
173
+ {
174
+ type: "button",
175
+ onClick: onResetAccount,
176
+ className: "cursor-pointer rounded-[6px] border border-white/20 bg-white/10 px-[0.7rem] py-[0.35rem] text-xs text-[#888] transition-all duration-150 hover:border-white/30 hover:bg-white/[0.15] hover:text-white",
177
+ children: "Reset Account"
178
+ }
179
+ ) : null
180
+ ] }),
181
+ /* @__PURE__ */ jsx("div", { className: "mt-3 h-px w-full bg-white/10" })
182
+ ] }),
183
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 pt-4", children: [
184
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
185
+ /* @__PURE__ */ jsxs("div", { children: [
186
+ /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Available Cash" }),
187
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children: formatCurrency(availableCash) })
188
+ ] }),
189
+ /* @__PURE__ */ jsxs("div", { children: [
190
+ /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Portfolio Value" }),
191
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-[1.25rem] font-semibold text-white", children: formatCurrency(portfolioValue) })
192
+ ] }),
193
+ /* @__PURE__ */ jsxs("div", { children: [
194
+ /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Total Return" }),
195
+ /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-[1.25rem] font-semibold", totalReturnClassName), children: formatPercent(totalReturnPercent) })
196
+ ] }),
197
+ /* @__PURE__ */ jsxs("div", { children: [
198
+ /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-[0.5px] text-white/50", children: "Unrealized P&L" }),
199
+ /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-[1.25rem] font-semibold", pnlClassName), children: formatSignedCurrency(unrealizedPnl) })
200
+ ] })
201
+ ] }),
202
+ /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
203
+ /* @__PURE__ */ jsx("p", { className: "m-0 text-[0.9rem] font-medium text-white/70", children: positionsHeading }),
204
+ /* @__PURE__ */ jsx("div", { className: "mt-3", children: children ? children : /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-[0.85rem] text-white/40", children: emptyPositionsText }) })
205
+ ] })
206
+ ] })
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ );
212
+ PortfolioSummary.displayName = "PortfolioSummary";
213
+ var clamp = (v, min, max) => Math.min(max, Math.max(min, v));
214
+ var fmt0 = (v) => Math.abs(v).toLocaleString(void 0, { maximumFractionDigits: 0 });
215
+ function HousePositionSlider({
216
+ tokenId,
217
+ tokenSymbol,
218
+ totalTokens,
219
+ currentPrice,
220
+ availableCash,
221
+ tokensHeld,
222
+ pendingOrders = [],
223
+ defaultOrderType = "market",
224
+ onConfirmOrder,
225
+ className,
226
+ ...props
227
+ }) {
228
+ const [orderMode, setOrderMode] = React5.useState("none");
229
+ const [buyTrackingMode, setBuyTrackingMode] = React5.useState("dollars");
230
+ const [deltaDollars, setDeltaDollars] = React5.useState(0);
231
+ const [deltaTokensBuy, setDeltaTokensBuy] = React5.useState(0);
232
+ const [deltaTokensSell, setDeltaTokensSell] = React5.useState(0);
233
+ const [isDragging, setIsDragging] = React5.useState(false);
234
+ const [orderType, setOrderType] = React5.useState(defaultOrderType);
235
+ const [limitPrice, setLimitPrice] = React5.useState(currentPrice);
236
+ const [limitPriceInput, setLimitPriceInput] = React5.useState(currentPrice.toFixed(2));
237
+ const [ownershipInput, setOwnershipInput] = React5.useState("");
238
+ const [tokenAmountInput, setTokenAmountInput] = React5.useState("");
239
+ const houseRef = React5.useRef(null);
240
+ React5.useEffect(() => {
241
+ setLimitPrice(currentPrice);
242
+ setLimitPriceInput(currentPrice.toFixed(2));
243
+ }, [currentPrice]);
244
+ const effectivePrice = orderType === "limit" ? limitPrice : currentPrice;
245
+ const holdingsValue = tokensHeld * effectivePrice;
246
+ const totalCapacity = holdingsValue + availableCash;
247
+ const pendingBuyValue = pendingOrders.filter((o) => o.type === "buy").reduce((s, o) => s + o.value, 0);
248
+ const pendingSellTokens = pendingOrders.filter((o) => o.type === "sell").reduce((s, o) => s + Math.abs(o.tokens), 0);
249
+ const effectiveAvailableCash = Math.max(0, availableCash - pendingBuyValue);
250
+ const effectiveTokensHeld = Math.max(0, tokensHeld - pendingSellTokens);
251
+ const baselinePct = totalCapacity <= 0 ? 0 : holdingsValue / totalCapacity * 100;
252
+ let deltaTokens = 0;
253
+ let deltaValue = 0;
254
+ let targetTokens = tokensHeld;
255
+ let targetValue = holdingsValue;
256
+ if (orderMode === "buy") {
257
+ if (buyTrackingMode === "tokens") {
258
+ deltaTokens = deltaTokensBuy;
259
+ deltaValue = deltaTokensBuy * effectivePrice;
260
+ } else {
261
+ deltaValue = deltaDollars;
262
+ deltaTokens = deltaDollars / (effectivePrice || 1);
263
+ }
264
+ } else if (orderMode === "sell") {
265
+ deltaTokens = deltaTokensSell;
266
+ deltaValue = deltaTokensSell * effectivePrice;
267
+ }
268
+ targetTokens = tokensHeld + deltaTokens;
269
+ targetValue = targetTokens * effectivePrice;
270
+ const targetPct = totalCapacity <= 0 ? 0 : targetValue / totalCapacity * 100;
271
+ const isIncrease = orderMode === "buy";
272
+ const hasChange = orderMode !== "none" && (Math.abs(deltaTokens) > 1e-3 || Math.abs(deltaValue) > 0.01);
273
+ const currentOwnership = totalTokens <= 0 ? 0 : tokensHeld / totalTokens * 100;
274
+ const targetOwnership = totalTokens <= 0 ? 0 : targetTokens / totalTokens * 100;
275
+ const estFeeTokens = Math.abs(deltaValue) * 5e-3 / (effectivePrice || 1);
276
+ const updateOrderFromTargetValue = React5.useCallback(
277
+ (newTargetValue) => {
278
+ const newDeltaValue = newTargetValue - holdingsValue;
279
+ if (newDeltaValue > 0) {
280
+ setOrderMode("buy");
281
+ setBuyTrackingMode("dollars");
282
+ setDeltaDollars(Math.min(newDeltaValue, effectiveAvailableCash));
283
+ setDeltaTokensBuy(0);
284
+ setDeltaTokensSell(0);
285
+ return;
286
+ }
287
+ if (newDeltaValue < 0) {
288
+ const newDeltaTokens = newTargetValue / (effectivePrice || 1) - tokensHeld;
289
+ setOrderMode("sell");
290
+ setBuyTrackingMode("dollars");
291
+ setDeltaTokensSell(Math.max(newDeltaTokens, -effectiveTokensHeld));
292
+ setDeltaDollars(0);
293
+ setDeltaTokensBuy(0);
294
+ return;
295
+ }
296
+ setOrderMode("none");
297
+ setBuyTrackingMode("dollars");
298
+ setDeltaDollars(0);
299
+ setDeltaTokensBuy(0);
300
+ setDeltaTokensSell(0);
301
+ },
302
+ [effectiveAvailableCash, effectivePrice, effectiveTokensHeld, holdingsValue, tokensHeld]
303
+ );
304
+ const updateOrderFromOwnership = React5.useCallback(
305
+ (newOwnershipPercent) => {
306
+ const nextOwnership = clamp(newOwnershipPercent, 0, 100);
307
+ const newTargetTokens = nextOwnership / 100 * totalTokens;
308
+ updateOrderFromTargetValue(newTargetTokens * effectivePrice);
309
+ },
310
+ [effectivePrice, totalTokens, updateOrderFromTargetValue]
311
+ );
312
+ const updateOrderFromTokenAmount = React5.useCallback(
313
+ (tokenAmountSigned) => {
314
+ if (tokenAmountSigned > 0) {
315
+ const maxTokens = effectiveAvailableCash / (effectivePrice || 1);
316
+ setOrderMode("buy");
317
+ setBuyTrackingMode("tokens");
318
+ setDeltaTokensBuy(Math.min(tokenAmountSigned, maxTokens));
319
+ setDeltaDollars(0);
320
+ setDeltaTokensSell(0);
321
+ return;
322
+ }
323
+ if (tokenAmountSigned < 0) {
324
+ setOrderMode("sell");
325
+ setBuyTrackingMode("dollars");
326
+ setDeltaTokensSell(Math.max(tokenAmountSigned, -effectiveTokensHeld));
327
+ setDeltaDollars(0);
328
+ setDeltaTokensBuy(0);
329
+ return;
330
+ }
331
+ setOrderMode("none");
332
+ setBuyTrackingMode("dollars");
333
+ setDeltaDollars(0);
334
+ setDeltaTokensBuy(0);
335
+ setDeltaTokensSell(0);
336
+ },
337
+ [effectiveAvailableCash, effectivePrice, effectiveTokensHeld]
338
+ );
339
+ const handleDragAtClientY = React5.useCallback(
340
+ (clientY) => {
341
+ if (!houseRef.current) return;
342
+ const rect = houseRef.current.getBoundingClientRect();
343
+ const y = clientY - rect.top;
344
+ const pct = clamp(100 - y / rect.height * 100, 0, 100);
345
+ updateOrderFromTargetValue(pct / 100 * totalCapacity);
346
+ },
347
+ [totalCapacity, updateOrderFromTargetValue]
348
+ );
349
+ const onMouseDown = (e) => {
350
+ e.preventDefault();
351
+ setIsDragging(true);
352
+ const onMove = (ev) => handleDragAtClientY(ev.clientY);
353
+ const onUp = () => {
354
+ setIsDragging(false);
355
+ document.removeEventListener("mousemove", onMove);
356
+ document.removeEventListener("mouseup", onUp);
357
+ };
358
+ document.addEventListener("mousemove", onMove);
359
+ document.addEventListener("mouseup", onUp);
360
+ };
361
+ const onTouchStart = () => {
362
+ setIsDragging(true);
363
+ const onMove = (ev) => {
364
+ const touch = ev.touches[0];
365
+ if (!touch) return;
366
+ handleDragAtClientY(touch.clientY);
367
+ };
368
+ const onEnd = () => {
369
+ setIsDragging(false);
370
+ document.removeEventListener("touchmove", onMove);
371
+ document.removeEventListener("touchend", onEnd);
372
+ };
373
+ document.addEventListener("touchmove", onMove);
374
+ document.addEventListener("touchend", onEnd);
375
+ };
376
+ const handleCancel = () => {
377
+ setOrderMode("none");
378
+ setBuyTrackingMode("dollars");
379
+ setDeltaDollars(0);
380
+ setDeltaTokensBuy(0);
381
+ setDeltaTokensSell(0);
382
+ };
383
+ const handleConfirm = () => {
384
+ if (!hasChange) return;
385
+ const priceToUse = orderType === "market" ? currentPrice : limitPrice;
386
+ onConfirmOrder?.({
387
+ side: isIncrease ? "buy" : "sell",
388
+ orderType,
389
+ tokenId,
390
+ tokenSymbol,
391
+ price: priceToUse,
392
+ deltaTokens,
393
+ deltaValue,
394
+ targetOwnership,
395
+ targetTokens,
396
+ targetValue
397
+ });
398
+ handleCancel();
399
+ };
400
+ const rectTop = 10;
401
+ const rectBottom = 150;
402
+ const totalFillableHeight = rectBottom - rectTop;
403
+ const baselineFillHeight = baselinePct / 100 * totalFillableHeight;
404
+ const targetFillHeight = targetPct / 100 * totalFillableHeight;
405
+ const baselineFillY = rectBottom - baselineFillHeight;
406
+ const targetFillY = rectBottom - targetFillHeight;
407
+ const showIncrease = targetPct > baselinePct;
408
+ const showDecrease = targetPct < baselinePct;
409
+ const valueLabel = orderType === "limit" ? `${tokenSymbol} Owned at Limit` : `${tokenSymbol} Owned`;
410
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative flex w-full flex-col items-center gap-6 rounded-[12px] bg-black/20 px-8 pb-6 pt-12", className), ...props, children: [
411
+ /* @__PURE__ */ jsx("div", { className: "absolute left-4 top-4 text-[1.1rem] font-semibold tracking-[0.5px] text-white", children: "Place Order" }),
412
+ hasChange ? /* @__PURE__ */ jsx(
413
+ "button",
414
+ {
415
+ type: "button",
416
+ onClick: handleCancel,
417
+ className: "absolute right-3 top-3 rounded-[6px] border border-white/20 bg-white/10 px-2.5 py-1.5 text-[0.7rem] text-[#888] transition-all duration-150 hover:border-white/30 hover:bg-white/[0.15] hover:text-white",
418
+ children: "\u2715 Cancel"
419
+ }
420
+ ) : null,
421
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
422
+ /* @__PURE__ */ jsx("div", { className: "mb-2 text-xs uppercase tracking-[1px] text-[#888]", children: valueLabel }),
423
+ /* @__PURE__ */ jsx("div", { className: "inline-flex items-baseline gap-2 text-[2rem] font-bold text-white", children: isDragging ? /* @__PURE__ */ jsxs(
424
+ "span",
425
+ {
426
+ className: cn("text-[2rem] font-semibold", deltaValue >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]"),
427
+ children: [
428
+ deltaValue > 0 ? "+" : deltaValue < 0 ? "-" : "",
429
+ "$",
430
+ fmt0(deltaValue)
431
+ ]
432
+ }
433
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
434
+ /* @__PURE__ */ jsxs("span", { children: [
435
+ "$",
436
+ fmt0(targetValue)
437
+ ] }),
438
+ hasChange ? /* @__PURE__ */ jsxs(
439
+ "span",
440
+ {
441
+ className: cn(
442
+ "relative top-[-0.5rem] text-[0.85rem] font-semibold",
443
+ deltaValue >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]"
444
+ ),
445
+ children: [
446
+ deltaValue > 0 ? "+" : deltaValue < 0 ? "-" : "",
447
+ fmt0(deltaValue)
448
+ ]
449
+ }
450
+ ) : null
451
+ ] }) })
452
+ ] }),
453
+ /* @__PURE__ */ jsx("div", { ref: houseRef, className: "h-[200px] w-[160px] select-none touch-none", style: { cursor: "ns-resize" }, onMouseDown, onTouchStart, children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 120 160", className: "h-full w-full overflow-visible", children: [
454
+ /* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "100", height: "140", rx: "8", fill: "rgba(255,255,255,0.04)", stroke: "rgba(255,255,255,0.10)" }),
455
+ /* @__PURE__ */ jsx("clipPath", { id: "loaf-clip", children: /* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "100", height: "140", rx: "8" }) }),
456
+ /* @__PURE__ */ jsxs("g", { clipPath: "url(#loaf-clip)", children: [
457
+ /* @__PURE__ */ jsx("rect", { x: "10", y: showDecrease ? targetFillY : baselineFillY, width: "100", height: showDecrease ? targetFillHeight : baselineFillHeight, fill: "rgba(220,175,120,0.7)" }),
458
+ showIncrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: targetFillY, width: "100", height: targetFillHeight - baselineFillHeight, fill: "rgba(14,203,129,0.35)" }) : null,
459
+ showDecrease ? /* @__PURE__ */ jsx("rect", { x: "10", y: baselineFillY, width: "100", height: baselineFillHeight - targetFillHeight, fill: "rgba(246,70,93,0.35)" }) : null,
460
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: targetFillY, x2: "108", y2: targetFillY, stroke: showIncrease ? "#0ecb81" : showDecrease ? "#f6465d" : "rgba(234,217,162,1)", strokeWidth: "2", strokeLinecap: "round" })
461
+ ] })
462
+ ] }) }),
463
+ /* @__PURE__ */ jsx(
464
+ "button",
465
+ {
466
+ type: "button",
467
+ disabled: !hasChange,
468
+ onClick: handleConfirm,
469
+ className: cn(
470
+ "w-full rounded-[10px] px-4 py-4 text-base font-semibold transition",
471
+ !hasChange ? "cursor-not-allowed bg-white/10 text-white/30" : isIncrease ? "bg-[#0ecb81] text-white hover:-translate-y-[1px] hover:shadow-[0_4px_12px_rgba(14,203,129,0.3)]" : "bg-[#f6465d] text-white hover:-translate-y-[1px] hover:shadow-[0_4px_12px_rgba(246,70,93,0.3)]"
472
+ ),
473
+ children: !hasChange ? "Adjust Position" : isIncrease ? `Buy $${fmt0(deltaValue)}` : `Sell $${fmt0(deltaValue)}`
474
+ }
475
+ ),
476
+ /* @__PURE__ */ jsxs("div", { className: "w-full border-t border-white/10 py-4 text-[0.85rem]", children: [
477
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
478
+ /* @__PURE__ */ jsxs("span", { className: "text-white/50", children: [
479
+ tokenSymbol,
480
+ " Ownership"
481
+ ] }),
482
+ /* @__PURE__ */ jsxs("span", { className: "text-white", children: [
483
+ currentOwnership.toFixed(2),
484
+ "%",
485
+ /* @__PURE__ */ jsx("span", { className: "mx-1.5 text-white/50", children: "\u2192" }),
486
+ /* @__PURE__ */ jsx(
487
+ "input",
488
+ {
489
+ type: "text",
490
+ value: ownershipInput || targetOwnership.toFixed(2),
491
+ onChange: (e) => {
492
+ const val = e.target.value;
493
+ if (val === "" || /^[0-9]*\.?[0-9]*$/.test(val)) setOwnershipInput(val);
494
+ },
495
+ onFocus: () => setOwnershipInput(targetOwnership.toFixed(2)),
496
+ onBlur: () => {
497
+ const num = Number.parseFloat(ownershipInput);
498
+ if (Number.isFinite(num)) updateOrderFromOwnership(num);
499
+ setOwnershipInput("");
500
+ },
501
+ onKeyDown: (e) => {
502
+ if (e.key === "Enter") e.target.blur();
503
+ },
504
+ className: cn(
505
+ "w-[70px] rounded-[4px] border bg-white/10 px-2 py-1 text-right font-semibold outline-none",
506
+ targetOwnership >= currentOwnership ? "border-[rgba(14,203,129,0.3)] text-[#0ecb81] focus:border-[#0ecb81]" : "border-[rgba(246,70,93,0.3)] text-[#f6465d] focus:border-[#f6465d]"
507
+ )
508
+ }
509
+ )
510
+ ] })
511
+ ] }),
512
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
513
+ /* @__PURE__ */ jsx("span", { className: "text-white/50", children: isIncrease ? "Buying" : "Selling" }),
514
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
515
+ orderMode === "buy" && buyTrackingMode === "dollars" ? /* @__PURE__ */ jsx("span", { className: "mr-1 text-[#0ecb81]", children: "~" }) : null,
516
+ /* @__PURE__ */ jsx(
517
+ "input",
518
+ {
519
+ type: "text",
520
+ value: tokenAmountInput || Math.abs(deltaTokens).toFixed(2),
521
+ onChange: (e) => {
522
+ const val = e.target.value;
523
+ if (val === "" || /^[0-9]*\.?[0-9]*$/.test(val)) setTokenAmountInput(val);
524
+ },
525
+ onFocus: () => setTokenAmountInput(Math.abs(deltaTokens).toFixed(2)),
526
+ onBlur: () => {
527
+ const num = Number.parseFloat(tokenAmountInput);
528
+ if (Number.isFinite(num) && num >= 0) {
529
+ const signed = isIncrease || orderMode === "none" ? num : -num;
530
+ updateOrderFromTokenAmount(signed);
531
+ }
532
+ setTokenAmountInput("");
533
+ },
534
+ onKeyDown: (e) => {
535
+ if (e.key === "Enter") e.target.blur();
536
+ },
537
+ className: cn(
538
+ "w-[90px] rounded-[4px] border bg-white/10 px-2 py-1 text-right font-semibold outline-none",
539
+ isIncrease ? "border-[rgba(14,203,129,0.3)] text-[#0ecb81] focus:border-[#0ecb81]" : "border-[rgba(246,70,93,0.3)] text-[#f6465d] focus:border-[#f6465d]"
540
+ )
541
+ }
542
+ ),
543
+ /* @__PURE__ */ jsx("span", { className: cn("font-semibold", isIncrease ? "text-[#0ecb81]" : "text-[#f6465d]"), children: "tokens" })
544
+ ] })
545
+ ] }),
546
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
547
+ /* @__PURE__ */ jsx("span", { className: "text-white/50", children: "Est. Fee" }),
548
+ /* @__PURE__ */ jsxs("span", { className: "text-white", children: [
549
+ estFeeTokens.toFixed(6),
550
+ " ",
551
+ tokenSymbol
552
+ ] })
553
+ ] })
554
+ ] }),
555
+ /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
556
+ /* @__PURE__ */ jsxs("div", { className: "mb-4 flex w-full rounded-[8px] bg-white/5 p-[3px]", children: [
557
+ /* @__PURE__ */ jsx(
558
+ "button",
559
+ {
560
+ type: "button",
561
+ onClick: () => setOrderType("market"),
562
+ className: cn(
563
+ "flex-1 rounded-[6px] px-3 py-2 text-[0.8rem] font-medium transition",
564
+ orderType === "market" ? "bg-[rgba(201,162,39,0.2)] text-[#C9A227]" : "text-white/50 hover:bg-white/5"
565
+ ),
566
+ children: "Market"
567
+ }
568
+ ),
569
+ /* @__PURE__ */ jsx(
570
+ "button",
571
+ {
572
+ type: "button",
573
+ onClick: () => setOrderType("limit"),
574
+ className: cn(
575
+ "flex-1 rounded-[6px] px-3 py-2 text-[0.8rem] font-medium transition",
576
+ orderType === "limit" ? "bg-[rgba(201,162,39,0.2)] text-[#C9A227]" : "text-white/50 hover:bg-white/5"
577
+ ),
578
+ children: "Limit"
579
+ }
580
+ )
581
+ ] }),
582
+ orderType === "limit" ? /* @__PURE__ */ jsxs("div", { className: "relative mb-4", children: [
583
+ /* @__PURE__ */ jsx(
584
+ "input",
585
+ {
586
+ type: "text",
587
+ value: limitPriceInput,
588
+ onChange: (e) => {
589
+ const input = e.target.value;
590
+ if (input === "" || /^[0-9]*\.?[0-9]*$/.test(input)) {
591
+ setLimitPriceInput(input);
592
+ const num = Number.parseFloat(input);
593
+ if (Number.isFinite(num) && num > 0) setLimitPrice(num);
594
+ }
595
+ },
596
+ onBlur: () => {
597
+ const num = Number.parseFloat(limitPriceInput);
598
+ if (Number.isFinite(num) && num > 0) {
599
+ setLimitPriceInput(num.toFixed(2));
600
+ setLimitPrice(num);
601
+ } else {
602
+ setLimitPriceInput(limitPrice.toFixed(2));
603
+ }
604
+ },
605
+ placeholder: "Price",
606
+ className: "w-full rounded-[8px] border border-white/10 bg-black/30 px-4 py-3 pr-14 text-[0.95rem] text-white outline-none focus:border-[#f0b90b]"
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsx("span", { className: "absolute right-4 top-1/2 -translate-y-1/2 text-[0.8rem] text-white/50", children: "USD" })
610
+ ] }) : null,
611
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-white/50", children: [
612
+ /* @__PURE__ */ jsxs("span", { children: [
613
+ "Available: $",
614
+ availableCash.toLocaleString()
615
+ ] }),
616
+ /* @__PURE__ */ jsx("button", { type: "button", className: "text-[#f0b90b] hover:underline", children: "Add Funds" })
617
+ ] })
618
+ ] })
619
+ ] });
620
+ }
621
+ var formatNumber = (value, precision) => value.toFixed(precision);
622
+ function DepthRow({
623
+ side,
624
+ price,
625
+ amount,
626
+ depthPct,
627
+ precision,
628
+ amountPrecision
629
+ }) {
630
+ const isAsk = side === "ask";
631
+ return /* @__PURE__ */ jsxs("div", { className: "relative grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
632
+ /* @__PURE__ */ jsx(
633
+ "div",
634
+ {
635
+ className: cn(
636
+ "absolute inset-y-0 right-0",
637
+ isAsk ? "bg-rose-900/30" : "bg-emerald-900/30"
638
+ ),
639
+ style: { width: `${clamp2(depthPct, 0, 100)}%` }
640
+ }
641
+ ),
642
+ /* @__PURE__ */ jsxs(
643
+ "div",
644
+ {
645
+ className: cn("relative z-[1] tabular-nums", isAsk ? "text-[#f6465d]" : "text-[#0ecb81]"),
646
+ children: [
647
+ "$",
648
+ formatNumber(price, precision)
649
+ ]
650
+ }
651
+ ),
652
+ /* @__PURE__ */ jsx("div", { className: "relative z-[1] text-right tabular-nums text-white/90", children: formatNumber(amount, amountPrecision) })
653
+ ] });
654
+ }
655
+ var clamp2 = (value, min, max) => Math.min(max, Math.max(min, value));
656
+ var Orderbook = React5.forwardRef(
657
+ ({
658
+ asks,
659
+ bids,
660
+ midPrice,
661
+ midChangePercent,
662
+ trades = [],
663
+ priceLabel = "Price (USD)",
664
+ amountLabel = "Amount",
665
+ precision = 2,
666
+ amountPrecision = 2,
667
+ defaultTab = "orderbook",
668
+ onTabChange,
669
+ rightHeader,
670
+ className,
671
+ ...props
672
+ }, ref) => {
673
+ const [tab, setTab] = React5.useState(defaultTab);
674
+ const [tradeFilter, setTradeFilter] = React5.useState("all");
675
+ React5.useEffect(() => {
676
+ setTab(defaultTab);
677
+ }, [defaultTab]);
678
+ const handleTab = (next) => {
679
+ setTab(next);
680
+ onTabChange?.(next);
681
+ };
682
+ const maxAskDepth = Math.max(1, ...asks.map((l) => l.depth ?? l.amount));
683
+ const maxBidDepth = Math.max(1, ...bids.map((l) => l.depth ?? l.amount));
684
+ const midClass = midChangePercent == null ? "text-white" : midChangePercent >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
685
+ const tradeFiltered = trades.filter((t) => tradeFilter === "all" || t.type === tradeFilter);
686
+ return /* @__PURE__ */ jsxs(
687
+ Card,
688
+ {
689
+ ref,
690
+ className: cn(
691
+ "w-full max-w-[520px] overflow-hidden rounded-[12px] border border-white/10 bg-black/30 text-white shadow-md",
692
+ className
693
+ ),
694
+ ...props,
695
+ children: [
696
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 pt-4", children: [
697
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
698
+ /* @__PURE__ */ jsxs(
699
+ "button",
700
+ {
701
+ type: "button",
702
+ onClick: () => handleTab("orderbook"),
703
+ className: cn(
704
+ "relative pb-2 text-sm font-semibold",
705
+ tab === "orderbook" ? "text-white" : "text-white/60"
706
+ ),
707
+ children: [
708
+ "Orderbook",
709
+ tab === "orderbook" ? /* @__PURE__ */ jsx("span", { className: "absolute -bottom-px left-0 h-[2px] w-full bg-[#C9A227]" }) : null
710
+ ]
711
+ }
712
+ ),
713
+ /* @__PURE__ */ jsxs(
714
+ "button",
715
+ {
716
+ type: "button",
717
+ onClick: () => handleTab("trades"),
718
+ className: cn(
719
+ "relative pb-2 text-sm font-medium",
720
+ tab === "trades" ? "text-white" : "text-white/60"
721
+ ),
722
+ children: [
723
+ "Trades",
724
+ tab === "trades" ? /* @__PURE__ */ jsx("span", { className: "absolute -bottom-px left-0 h-[2px] w-full bg-[#C9A227]" }) : null
725
+ ]
726
+ }
727
+ )
728
+ ] }),
729
+ tab === "trades" ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs", children: [
730
+ /* @__PURE__ */ jsx(
731
+ "button",
732
+ {
733
+ type: "button",
734
+ onClick: () => setTradeFilter("all"),
735
+ className: cn(
736
+ "rounded-md px-2 py-1 transition",
737
+ tradeFilter === "all" ? "bg-white/10 text-white" : "text-white/70 hover:bg-white/10"
738
+ ),
739
+ children: "All"
740
+ }
741
+ ),
742
+ /* @__PURE__ */ jsx(
743
+ "button",
744
+ {
745
+ type: "button",
746
+ onClick: () => setTradeFilter("buy"),
747
+ className: cn(
748
+ "rounded-md px-2 py-1 transition",
749
+ tradeFilter === "buy" ? "bg-white/10 text-white" : "text-white/70 hover:bg-white/10"
750
+ ),
751
+ children: "Buy"
752
+ }
753
+ ),
754
+ /* @__PURE__ */ jsx(
755
+ "button",
756
+ {
757
+ type: "button",
758
+ onClick: () => setTradeFilter("sell"),
759
+ className: cn(
760
+ "rounded-md px-2 py-1 transition",
761
+ tradeFilter === "sell" ? "bg-white/10 text-white" : "text-white/70 hover:bg-white/10"
762
+ ),
763
+ children: "Sell"
764
+ }
765
+ )
766
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: rightHeader })
767
+ ] }),
768
+ /* @__PURE__ */ jsxs("div", { className: "px-4 pb-3 pt-2", children: [
769
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 px-3 py-2 text-xs text-white/60", children: [
770
+ /* @__PURE__ */ jsx("div", { children: priceLabel }),
771
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: amountLabel })
772
+ ] }),
773
+ tab === "trades" ? /* @__PURE__ */ jsx(
774
+ "div",
775
+ {
776
+ className: "max-h-[380px] overflow-y-auto overflow-x-hidden",
777
+ style: { scrollbarGutter: "stable" },
778
+ 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) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3 px-3 py-1.5", children: [
779
+ /* @__PURE__ */ jsxs(
780
+ "div",
781
+ {
782
+ className: cn(
783
+ "tabular-nums",
784
+ trade.type === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]"
785
+ ),
786
+ children: [
787
+ "$",
788
+ formatNumber(trade.price, precision)
789
+ ]
790
+ }
791
+ ),
792
+ /* @__PURE__ */ jsx("div", { className: "text-right tabular-nums text-white/90", children: formatNumber(trade.amount, amountPrecision) })
793
+ ] }, `${trade.type}-${trade.price}-${trade.amount}-${trade.time ?? i}`)) })
794
+ }
795
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
796
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: asks.map((l, idx) => /* @__PURE__ */ jsx(
797
+ DepthRow,
798
+ {
799
+ side: "ask",
800
+ price: l.price,
801
+ amount: l.amount,
802
+ depthPct: (l.depth ?? l.amount) / maxAskDepth * 100,
803
+ precision,
804
+ amountPrecision
805
+ },
806
+ `ask-${idx}-${l.price}-${l.amount}`
807
+ )) }),
808
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 grid grid-cols-2 items-center gap-3 bg-[#0b1a24] px-3 py-2", children: [
809
+ /* @__PURE__ */ jsxs("div", { className: cn("text-lg font-semibold tabular-nums", midClass), children: [
810
+ "$",
811
+ formatNumber(midPrice, precision),
812
+ midChangePercent == null ? null : /* @__PURE__ */ jsxs("span", { className: "ml-2 text-sm font-semibold", children: [
813
+ midChangePercent >= 0 ? "+" : "",
814
+ midChangePercent.toFixed(2),
815
+ "%"
816
+ ] })
817
+ ] }),
818
+ /* @__PURE__ */ jsx("div", {})
819
+ ] }),
820
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-white/5", children: bids.map((l, idx) => /* @__PURE__ */ jsx(
821
+ DepthRow,
822
+ {
823
+ side: "bid",
824
+ price: l.price,
825
+ amount: l.amount,
826
+ depthPct: (l.depth ?? l.amount) / maxBidDepth * 100,
827
+ precision,
828
+ amountPrecision
829
+ },
830
+ `bid-${idx}-${l.price}-${l.amount}`
831
+ )) })
832
+ ] })
833
+ ] })
834
+ ]
835
+ }
836
+ );
837
+ }
838
+ );
839
+ Orderbook.displayName = "Orderbook";
840
+ var PropertyTour = React5.forwardRef(
841
+ ({
842
+ className,
843
+ title,
844
+ src,
845
+ poster,
846
+ autoPlay = true,
847
+ muted = true,
848
+ loop = true,
849
+ controls = true,
850
+ playsInline = true,
851
+ ...props
852
+ }, ref) => {
853
+ const videoRef = React5.useRef(null);
854
+ React5.useEffect(() => {
855
+ const video = videoRef.current;
856
+ if (!video) return;
857
+ const handleFullscreenChange = () => {
858
+ const d = document;
859
+ const isFullscreen = !!(d.fullscreenElement || d.webkitFullscreenElement || d.mozFullScreenElement || d.msFullscreenElement);
860
+ if (isFullscreen) {
861
+ video.style.objectFit = "contain";
862
+ video.style.width = "100vw";
863
+ video.style.height = "100vh";
864
+ video.style.position = "fixed";
865
+ video.style.top = "0";
866
+ video.style.left = "0";
867
+ video.style.transform = "none";
868
+ video.style.zIndex = "9999";
869
+ } else {
870
+ video.style.objectFit = "cover";
871
+ video.style.width = "100%";
872
+ video.style.height = "100%";
873
+ video.style.position = "absolute";
874
+ video.style.top = "0";
875
+ video.style.left = "0";
876
+ video.style.transform = "none";
877
+ video.style.zIndex = "auto";
878
+ }
879
+ };
880
+ video.addEventListener("fullscreenchange", handleFullscreenChange);
881
+ video.addEventListener("webkitfullscreenchange", handleFullscreenChange);
882
+ video.addEventListener("mozfullscreenchange", handleFullscreenChange);
883
+ video.addEventListener("MSFullscreenChange", handleFullscreenChange);
884
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
885
+ document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
886
+ document.addEventListener("mozfullscreenchange", handleFullscreenChange);
887
+ document.addEventListener("MSFullscreenChange", handleFullscreenChange);
888
+ return () => {
889
+ video.removeEventListener("fullscreenchange", handleFullscreenChange);
890
+ video.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
891
+ video.removeEventListener("mozfullscreenchange", handleFullscreenChange);
892
+ video.removeEventListener("MSFullscreenChange", handleFullscreenChange);
893
+ document.removeEventListener("fullscreenchange", handleFullscreenChange);
894
+ document.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
895
+ document.removeEventListener("mozfullscreenchange", handleFullscreenChange);
896
+ document.removeEventListener("MSFullscreenChange", handleFullscreenChange);
897
+ };
898
+ }, []);
899
+ return /* @__PURE__ */ jsxs(
900
+ Card,
901
+ {
902
+ ref,
903
+ className: cn(
904
+ "w-full max-w-[820px] rounded-[12px] border border-white/10 bg-black/30 text-white backdrop-blur-md",
905
+ className
906
+ ),
907
+ ...props,
908
+ children: [
909
+ /* @__PURE__ */ jsx(CardHeader, { className: "px-6 pb-0 pt-6", children: /* @__PURE__ */ jsx(CardTitle, { className: "m-0 text-lg font-semibold text-white", children: title }) }),
910
+ /* @__PURE__ */ jsx("div", { className: "px-6 pb-6 pt-5", children: /* @__PURE__ */ jsx("div", { className: "relative aspect-video w-full overflow-hidden rounded-lg bg-black", children: /* @__PURE__ */ jsxs(
911
+ "video",
912
+ {
913
+ ref: videoRef,
914
+ className: "absolute inset-0 h-full w-full object-cover object-center",
915
+ controls,
916
+ loop,
917
+ autoPlay,
918
+ muted,
919
+ playsInline,
920
+ poster,
921
+ children: [
922
+ /* @__PURE__ */ jsx("source", { src }),
923
+ "Your browser does not support the video tag."
924
+ ]
925
+ }
926
+ ) }) })
927
+ ]
928
+ }
929
+ );
930
+ }
931
+ );
932
+ PropertyTour.displayName = "PropertyTour";
933
+ var TYPE_META = {
934
+ property: {
935
+ label: "Property Update",
936
+ accent: "#f8d12f",
937
+ pillBg: "rgba(248, 209, 47, 0.12)",
938
+ pillBorder: "rgba(248, 209, 47, 0.45)",
939
+ pillColor: "#f8d12f",
940
+ icon: Building2
941
+ },
942
+ market: {
943
+ label: "Market Insight",
944
+ accent: "#0ecb81",
945
+ pillBg: "rgba(14, 203, 129, 0.12)",
946
+ pillBorder: "rgba(14, 203, 129, 0.45)",
947
+ pillColor: "#0ecb81",
948
+ icon: LineChart
949
+ },
950
+ portfolio: {
951
+ label: "Portfolio Signal",
952
+ accent: "#6c8cff",
953
+ pillBg: "rgba(108, 140, 255, 0.12)",
954
+ pillBorder: "rgba(108, 140, 255, 0.45)",
955
+ pillColor: "#c9d5ff",
956
+ icon: Sparkles
957
+ }
958
+ };
959
+ var getTypeMeta = (type) => {
960
+ if (!type) return TYPE_META.property;
961
+ const key = type;
962
+ if (key in TYPE_META) return TYPE_META[key];
963
+ return {
964
+ label: type.toString(),
965
+ accent: "#f5f5f5",
966
+ pillBg: "rgba(255,255,255,0.08)",
967
+ pillBorder: "rgba(255,255,255,0.25)",
968
+ pillColor: "#ffffff",
969
+ icon: Newspaper
970
+ };
971
+ };
972
+ var formatDate = (value) => {
973
+ const date = typeof value === "string" ? new Date(value) : value;
974
+ if (Number.isNaN(date.getTime())) return typeof value === "string" ? value : "";
975
+ return date.toLocaleDateString(void 0, {
976
+ month: "short",
977
+ day: "numeric",
978
+ year: "numeric"
979
+ });
980
+ };
981
+ var PropertyNewsUpdates = React5.forwardRef(
982
+ ({ className, heading = "Latest property intelligence", subheading, items, emptyState, ...props }, ref) => {
983
+ const hasItems = Array.isArray(items) && items.length > 0;
984
+ return /* @__PURE__ */ jsxs(
985
+ "div",
986
+ {
987
+ ref,
988
+ className: cn(
989
+ "w-full max-w-[480px] rounded-[20px] border border-white/10 bg-gradient-to-br from-[#06090f] via-[#0f1621] to-[#111b2a] p-6 text-white shadow-[0_30px_80px_rgba(3,7,18,0.65)] backdrop-blur-xl",
990
+ className
991
+ ),
992
+ ...props,
993
+ children: [
994
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
995
+ /* @__PURE__ */ jsx("p", { className: "text-[0.85rem] uppercase tracking-[0.25em] text-white/50", children: heading }),
996
+ subheading ? /* @__PURE__ */ jsx("p", { className: "text-sm text-white/60", children: subheading }) : null
997
+ ] }),
998
+ /* @__PURE__ */ jsx("div", { className: "mt-5 flex flex-col gap-4", children: hasItems ? items.map((item, index) => {
999
+ const meta = getTypeMeta(item.type);
1000
+ const Icon = meta.icon;
1001
+ const key = item.id ?? `${item.title}-${index}`;
1002
+ const content = /* @__PURE__ */ jsxs(
1003
+ "div",
1004
+ {
1005
+ className: "relative flex w-full gap-4 rounded-2xl border border-white/5 bg-white/[0.04] p-4 transition hover:border-white/15 hover:bg-white/[0.06]",
1006
+ children: [
1007
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
1008
+ /* @__PURE__ */ jsx(
1009
+ "div",
1010
+ {
1011
+ className: "flex h-12 w-12 items-center justify-center rounded-full border text-white",
1012
+ style: {
1013
+ background: meta.pillBg,
1014
+ borderColor: meta.pillBorder,
1015
+ color: meta.pillColor
1016
+ },
1017
+ children: /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5" })
1018
+ }
1019
+ ),
1020
+ index !== items.length - 1 ? /* @__PURE__ */ jsx("div", { className: "mt-2 h-full w-px flex-1 bg-white/10" }) : null
1021
+ ] }),
1022
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col", children: [
1023
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
1024
+ /* @__PURE__ */ jsx("span", { className: "text-[0.7rem] font-semibold uppercase tracking-[0.3em]", style: { color: meta.accent }, children: meta.label }),
1025
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center text-xs text-white/60", children: [
1026
+ /* @__PURE__ */ jsx(CalendarDays, { className: "mr-1 h-3.5 w-3.5" }),
1027
+ formatDate(item.date)
1028
+ ] })
1029
+ ] }),
1030
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-base font-semibold leading-snug", children: item.title }),
1031
+ item.description ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-white/65", children: item.description }) : null,
1032
+ (item.href || item.onAction) && item.actionLabel ? /* @__PURE__ */ jsxs(
1033
+ "button",
1034
+ {
1035
+ type: "button",
1036
+ className: "group mt-3 inline-flex items-center gap-1 text-sm font-semibold text-white transition hover:text-white/80",
1037
+ onClick: () => {
1038
+ if (item.href) {
1039
+ window?.open?.(item.href, "_blank", "noopener,noreferrer");
1040
+ }
1041
+ item.onAction?.(item);
1042
+ },
1043
+ children: [
1044
+ item.actionLabel,
1045
+ /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-4 w-4 transition group-hover:translate-x-0.5 group-hover:-translate-y-0.5" })
1046
+ ]
1047
+ }
1048
+ ) : null
1049
+ ] })
1050
+ ]
1051
+ },
1052
+ key
1053
+ );
1054
+ return content;
1055
+ }) : emptyState ?? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center rounded-2xl border border-dashed border-white/20 px-6 py-10 text-center text-sm text-white/60", children: [
1056
+ /* @__PURE__ */ jsx(Newspaper, { className: "mb-3 h-8 w-8 text-white/40" }),
1057
+ "No property news yet. Updates will land here as soon as we receive new intelligence."
1058
+ ] }) })
1059
+ ]
1060
+ }
1061
+ );
1062
+ }
1063
+ );
1064
+ PropertyNewsUpdates.displayName = "PropertyNewsUpdates";
1065
+ var clampPct = (pct) => Math.min(100, Math.max(0, pct));
1066
+ var EditIcon = ({ className }) => /* @__PURE__ */ jsxs(
1067
+ "svg",
1068
+ {
1069
+ viewBox: "0 0 24 24",
1070
+ fill: "none",
1071
+ xmlns: "http://www.w3.org/2000/svg",
1072
+ className,
1073
+ children: [
1074
+ /* @__PURE__ */ jsx(
1075
+ "path",
1076
+ {
1077
+ d: "M12 20H21",
1078
+ stroke: "currentColor",
1079
+ strokeWidth: "2",
1080
+ strokeLinecap: "round",
1081
+ strokeLinejoin: "round"
1082
+ }
1083
+ ),
1084
+ /* @__PURE__ */ jsx(
1085
+ "path",
1086
+ {
1087
+ d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5Z",
1088
+ stroke: "currentColor",
1089
+ strokeWidth: "2",
1090
+ strokeLinecap: "round",
1091
+ strokeLinejoin: "round"
1092
+ }
1093
+ )
1094
+ ]
1095
+ }
1096
+ );
1097
+ var YourOrders = React5.forwardRef(
1098
+ ({
1099
+ className,
1100
+ title = "Your Orders",
1101
+ orders,
1102
+ onEditPrice,
1103
+ onEditAmount,
1104
+ onCancel,
1105
+ ...props
1106
+ }, ref) => {
1107
+ return /* @__PURE__ */ jsxs(
1108
+ Card,
1109
+ {
1110
+ ref,
1111
+ className: cn(
1112
+ "w-full min-h-[301.52px] rounded-[12px] border border-white/10 bg-black/30 text-white backdrop-blur-md max-[1024px]:min-h-[250px] max-[480px]:min-h-[200px]",
1113
+ className
1114
+ ),
1115
+ ...props,
1116
+ children: [
1117
+ /* @__PURE__ */ jsx(CardHeader, { className: "px-6 pb-2 pt-6", children: /* @__PURE__ */ jsx(CardTitle, { className: "m-0 text-[1.1rem] font-semibold text-white", children: title }) }),
1118
+ /* @__PURE__ */ jsxs("div", { className: "px-6 pb-6 pt-2", children: [
1119
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1.2fr_0.8fr_1fr_1fr_1fr_1fr_1.2fr_0.8fr] border-b border-white/10 pb-2 text-[0.85rem] font-medium text-white/60", children: [
1120
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Asset" }),
1121
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Type" }),
1122
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Date" }),
1123
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Price" }),
1124
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Amount" }),
1125
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Total" }),
1126
+ /* @__PURE__ */ jsx("div", { className: "px-2", children: "Filled" }),
1127
+ /* @__PURE__ */ jsx("div", { className: "px-2 text-center", children: "Actions" })
1128
+ ] }),
1129
+ orders.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-10 text-center text-sm text-white/50", children: "No orders" }) : /* @__PURE__ */ jsx("div", { children: orders.map((order) => {
1130
+ const sideClass = order.side === "buy" ? "text-[#0ecb81]" : "text-[#f6465d]";
1131
+ const filled = clampPct(order.filledPercent);
1132
+ const canEditPrice = Boolean(onEditPrice);
1133
+ const canEditAmount = Boolean(onEditAmount);
1134
+ const canCancel = Boolean(onCancel);
1135
+ return /* @__PURE__ */ jsxs(
1136
+ "div",
1137
+ {
1138
+ className: "grid grid-cols-[1.5fr_0.8fr_0.8fr_1fr_0.8fr_1fr_1fr_0.8fr] items-center border-b border-white/5 py-2 text-[0.9rem] transition-colors hover:bg-white/[0.03]",
1139
+ children: [
1140
+ /* @__PURE__ */ jsx("div", { className: "truncate px-2 font-medium", children: order.asset }),
1141
+ /* @__PURE__ */ jsx("div", { className: cn("px-2 font-medium uppercase", sideClass), children: order.side }),
1142
+ /* @__PURE__ */ jsx("div", { className: "px-2 font-medium", children: order.date }),
1143
+ /* @__PURE__ */ jsxs("div", { className: "px-2 font-medium", children: [
1144
+ /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
1145
+ "$",
1146
+ order.price.toLocaleString()
1147
+ ] }),
1148
+ /* @__PURE__ */ jsx(
1149
+ "button",
1150
+ {
1151
+ type: "button",
1152
+ onClick: canEditPrice ? () => onEditPrice?.(order) : void 0,
1153
+ className: cn(
1154
+ "ml-1 inline-flex items-center justify-center text-white/60 transition-colors",
1155
+ canEditPrice ? "cursor-pointer hover:text-[#C9A227] active:translate-y-px" : "cursor-default"
1156
+ ),
1157
+ "aria-label": "Edit price",
1158
+ children: /* @__PURE__ */ jsx(EditIcon, { className: "h-[14px] w-[14px]" })
1159
+ }
1160
+ )
1161
+ ] }),
1162
+ /* @__PURE__ */ jsxs("div", { className: "px-2 font-medium", children: [
1163
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: order.amount.toLocaleString() }),
1164
+ /* @__PURE__ */ jsx(
1165
+ "button",
1166
+ {
1167
+ type: "button",
1168
+ onClick: canEditAmount ? () => onEditAmount?.(order) : void 0,
1169
+ className: cn(
1170
+ "ml-1 inline-flex items-center justify-center text-white/60 transition-colors",
1171
+ canEditAmount ? "cursor-pointer hover:text-[#C9A227] active:translate-y-px" : "cursor-default"
1172
+ ),
1173
+ "aria-label": "Edit amount",
1174
+ children: /* @__PURE__ */ jsx(EditIcon, { className: "h-[14px] w-[14px]" })
1175
+ }
1176
+ )
1177
+ ] }),
1178
+ /* @__PURE__ */ jsxs("div", { className: "px-2 font-medium tabular-nums", children: [
1179
+ "$",
1180
+ order.total.toLocaleString()
1181
+ ] }),
1182
+ /* @__PURE__ */ jsxs("div", { className: "px-2", children: [
1183
+ /* @__PURE__ */ jsxs("div", { className: "text-[0.875rem] font-medium tabular-nums", children: [
1184
+ filled.toFixed(0),
1185
+ "%"
1186
+ ] }),
1187
+ /* @__PURE__ */ jsx("div", { className: "mt-1 h-1 w-4/5 overflow-hidden rounded-sm bg-white/10", children: /* @__PURE__ */ jsx("div", { className: "h-full rounded-sm bg-[#C9A227]", style: { width: `${filled}%` } }) })
1188
+ ] }),
1189
+ /* @__PURE__ */ jsx("div", { className: "px-2 text-center", children: /* @__PURE__ */ jsx(
1190
+ "button",
1191
+ {
1192
+ type: "button",
1193
+ onClick: canCancel ? () => onCancel?.(order) : void 0,
1194
+ className: cn(
1195
+ "rounded border border-white/40 px-3 py-1 text-[0.8rem] text-white/70 transition-colors",
1196
+ canCancel ? "cursor-pointer hover:bg-white/10 active:text-[#f6465d] active:border-[#f6465d] active:translate-y-px" : "cursor-default"
1197
+ ),
1198
+ children: "Cancel"
1199
+ }
1200
+ ) })
1201
+ ]
1202
+ },
1203
+ order.id
1204
+ );
1205
+ }) })
1206
+ ] })
1207
+ ]
1208
+ }
1209
+ );
1210
+ }
1211
+ );
1212
+ YourOrders.displayName = "YourOrders";
1213
+ var defaultRanges = ["1D", "1W", "1M", "3M", "1Y"];
1214
+ var formatPrice = (value, currencySymbol) => {
1215
+ return `${currencySymbol}${value.toLocaleString(void 0, {
1216
+ minimumFractionDigits: 2,
1217
+ maximumFractionDigits: 2
1218
+ })}`;
1219
+ };
1220
+ var PriceChart = React5.forwardRef(
1221
+ ({
1222
+ className,
1223
+ title = "Price Chart",
1224
+ ranges = defaultRanges,
1225
+ selectedRange,
1226
+ onRangeChange,
1227
+ data,
1228
+ price,
1229
+ changePercent,
1230
+ currencySymbol = "$",
1231
+ height = 301.52,
1232
+ ...props
1233
+ }, ref) => {
1234
+ const containerRef = React5.useRef(null);
1235
+ const chartRef = React5.useRef(null);
1236
+ const seriesRef = React5.useRef(null);
1237
+ const priceLineRef = React5.useRef(null);
1238
+ const [hoveredRange, setHoveredRange] = React5.useState(null);
1239
+ const resolvedPrice = React5.useMemo(() => {
1240
+ if (price != null) return price;
1241
+ const last = data.at(-1);
1242
+ return last?.close;
1243
+ }, [data, price]);
1244
+ const inferredChangePercent = React5.useMemo(() => {
1245
+ if (changePercent != null) return changePercent;
1246
+ const first = data[0]?.open;
1247
+ const last = data.at(-1)?.close;
1248
+ if (first == null || last == null || first === 0) return void 0;
1249
+ return (last - first) / first * 100;
1250
+ }, [changePercent, data]);
1251
+ React5.useEffect(() => {
1252
+ const el = containerRef.current;
1253
+ if (!el) return;
1254
+ const chart = createChart(el, {
1255
+ autoSize: true,
1256
+ layout: {
1257
+ background: { color: "transparent" },
1258
+ textColor: "rgba(255,255,255,0.55)",
1259
+ fontFamily: "inherit"
1260
+ },
1261
+ grid: {
1262
+ vertLines: { color: "rgba(255,255,255,0.06)" },
1263
+ horzLines: { color: "rgba(255,255,255,0.06)" }
1264
+ },
1265
+ rightPriceScale: {
1266
+ borderColor: "rgba(230, 200, 126, 0.25)",
1267
+ textColor: "rgba(230, 200, 126, 0.7)"
1268
+ },
1269
+ timeScale: {
1270
+ borderColor: "rgba(255,255,255,0.06)",
1271
+ timeVisible: true,
1272
+ secondsVisible: false
1273
+ },
1274
+ crosshair: {
1275
+ vertLine: { color: "rgba(255,255,255,0.12)" },
1276
+ horzLine: { color: "rgba(255,255,255,0.12)" }
1277
+ }
1278
+ });
1279
+ const series = chart.addCandlestickSeries({
1280
+ upColor: "#0ecb81",
1281
+ downColor: "#f6465d",
1282
+ borderVisible: false,
1283
+ wickUpColor: "#0ecb81",
1284
+ wickDownColor: "#f6465d"
1285
+ });
1286
+ chartRef.current = chart;
1287
+ seriesRef.current = series;
1288
+ return () => {
1289
+ chartRef.current = null;
1290
+ seriesRef.current = null;
1291
+ chart.remove();
1292
+ };
1293
+ }, []);
1294
+ React5.useEffect(() => {
1295
+ const chart = chartRef.current;
1296
+ const series = seriesRef.current;
1297
+ if (!chart || !series) return;
1298
+ series.setData(data);
1299
+ if (priceLineRef.current) {
1300
+ series.removePriceLine(priceLineRef.current);
1301
+ priceLineRef.current = null;
1302
+ }
1303
+ if (resolvedPrice != null) {
1304
+ const priceLineColor = "rgba(230, 200, 126, 0.9)";
1305
+ priceLineRef.current = series.createPriceLine({
1306
+ price: resolvedPrice,
1307
+ color: priceLineColor,
1308
+ lineWidth: 1,
1309
+ lineStyle: 2,
1310
+ axisLabelVisible: true,
1311
+ title: resolvedPrice.toFixed(2)
1312
+ });
1313
+ }
1314
+ chart.timeScale().fitContent();
1315
+ }, [data, resolvedPrice]);
1316
+ const sign = inferredChangePercent == null ? null : inferredChangePercent >= 0 ? "+" : "";
1317
+ const changeClass = inferredChangePercent == null ? "" : inferredChangePercent >= 0 ? "text-[#0ecb81]" : "text-[#f6465d]";
1318
+ const badgeClass = inferredChangePercent == null ? "" : inferredChangePercent >= 0 ? "bg-[#0ecb81]/15 text-[#0ecb81]" : "bg-[#f6465d]/15 text-[#f6465d]";
1319
+ const btnBaseStyle = {
1320
+ backgroundColor: "var(--color-card-dark, rgba(255, 255, 255, 0.05))",
1321
+ borderColor: "var(--color-border, rgba(255, 255, 255, 0.12))",
1322
+ color: "var(--color-text-secondary, rgba(255, 255, 255, 0.7))"
1323
+ };
1324
+ const btnHoverStyle = {
1325
+ backgroundColor: "var(--color-accent-dark, rgba(230, 200, 126, 0.15))",
1326
+ color: "var(--color-text, #ffffff)"
1327
+ };
1328
+ const btnActiveStyle = {
1329
+ backgroundColor: "var(--color-accent, #e6c87e)",
1330
+ borderColor: "var(--color-accent, #e6c87e)",
1331
+ color: "#000000"
1332
+ };
1333
+ return /* @__PURE__ */ jsxs(
1334
+ Card,
1335
+ {
1336
+ ref,
1337
+ className: cn(
1338
+ "w-full min-h-[450px] rounded-lg border border-white/10 bg-black/30 text-white backdrop-blur-md",
1339
+ className
1340
+ ),
1341
+ ...props,
1342
+ children: [
1343
+ /* @__PURE__ */ jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4 px-6 pb-2 pt-6", children: [
1344
+ /* @__PURE__ */ jsxs("div", { children: [
1345
+ /* @__PURE__ */ jsx(CardTitle, { className: "m-0 text-[1.1rem] font-semibold text-white", children: title }),
1346
+ /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: ranges.map((r) => {
1347
+ const active = r === selectedRange;
1348
+ const hovered = hoveredRange === r;
1349
+ const style = {
1350
+ ...btnBaseStyle,
1351
+ ...hovered ? btnHoverStyle : null,
1352
+ ...active ? btnActiveStyle : null
1353
+ };
1354
+ return /* @__PURE__ */ jsx(
1355
+ "button",
1356
+ {
1357
+ type: "button",
1358
+ onClick: () => onRangeChange?.(r),
1359
+ onMouseEnter: () => setHoveredRange(r),
1360
+ onMouseLeave: () => setHoveredRange((prev) => prev === r ? null : prev),
1361
+ style,
1362
+ className: cn(
1363
+ "rounded border px-3 py-1 text-[0.85rem] font-medium transition-all duration-200"
1364
+ ),
1365
+ children: r
1366
+ },
1367
+ r
1368
+ );
1369
+ }) })
1370
+ ] }),
1371
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1372
+ resolvedPrice == null ? null : /* @__PURE__ */ jsx("div", { className: cn("text-xl font-semibold tabular-nums", changeClass), children: formatPrice(resolvedPrice, currencySymbol) }),
1373
+ inferredChangePercent == null ? null : /* @__PURE__ */ jsxs("div", { className: cn("rounded-md px-2 py-1 text-xs font-semibold tabular-nums", badgeClass), children: [
1374
+ sign,
1375
+ inferredChangePercent?.toFixed(2),
1376
+ "%"
1377
+ ] })
1378
+ ] })
1379
+ ] }),
1380
+ /* @__PURE__ */ jsx("div", { className: "px-6 pb-6 pt-2", children: /* @__PURE__ */ jsx(
1381
+ "div",
1382
+ {
1383
+ ref: containerRef,
1384
+ className: "w-full overflow-hidden rounded-lg",
1385
+ style: { height }
1386
+ }
1387
+ ) })
1388
+ ]
1389
+ }
1390
+ );
1391
+ }
1392
+ );
1393
+ PriceChart.displayName = "PriceChart";
1394
+ var formatPrice2 = (value, currencySymbol) => {
1395
+ return `${currencySymbol}${value.toLocaleString(void 0, {
1396
+ minimumFractionDigits: 3,
1397
+ maximumFractionDigits: 3
1398
+ })}`;
1399
+ };
1400
+ var PropertyHeroHeader = React5.forwardRef(
1401
+ ({
1402
+ className,
1403
+ imageUrl,
1404
+ imageAlt,
1405
+ name,
1406
+ location,
1407
+ price,
1408
+ currencySymbol = "$",
1409
+ changePercent,
1410
+ beds,
1411
+ baths,
1412
+ cars,
1413
+ propertyTypeLabel,
1414
+ onTrade,
1415
+ onMakeOffer,
1416
+ ...props
1417
+ }, ref) => {
1418
+ const isPositive = changePercent == null ? void 0 : changePercent >= 0;
1419
+ const tradeHoverColor = "var(--color-accent-hover, #f8d12f)";
1420
+ return /* @__PURE__ */ jsxs(
1421
+ "div",
1422
+ {
1423
+ ref,
1424
+ className: cn(
1425
+ "relative w-full overflow-hidden bg-black h-[500px] rounded-[12px] max-[768px]:h-[400px] max-[768px]:rounded-lg max-[480px]:h-[350px] max-[480px]:rounded-md",
1426
+ className
1427
+ ),
1428
+ ...props,
1429
+ children: [
1430
+ /* @__PURE__ */ jsx(
1431
+ "img",
1432
+ {
1433
+ src: imageUrl,
1434
+ alt: imageAlt ?? name,
1435
+ className: "h-full w-full object-cover object-center block max-w-none min-w-[120%] min-h-[120%]",
1436
+ style: { transform: "scale(1.0)", transformOrigin: "center" }
1437
+ }
1438
+ ),
1439
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 flex w-full items-end justify-between p-8 max-[768px]:flex-col max-[768px]:items-start max-[768px]:gap-4 max-[768px]:p-6 max-[480px]:p-4", children: [
1440
+ /* @__PURE__ */ jsxs("div", { className: "inline-block w-auto max-w-[70%] rounded-lg bg-black/15 px-4 py-3 text-white shadow-[0px_1px_1px_rgba(0,0,0,0.3)] backdrop-blur-[3px] max-[768px]:w-full max-[768px]:max-w-full max-[768px]:px-3 max-[768px]:py-3 max-[480px]:px-3 max-[480px]:py-2", children: [
1441
+ /* @__PURE__ */ jsx("h1", { className: "mb-2 text-[2.5rem] leading-tight text-white [text-shadow:0_2px_4px_rgba(0,0,0,0.3)] max-[768px]:mb-[0.4rem] max-[768px]:text-[2rem] max-[480px]:mb-[0.3rem] max-[480px]:text-[1.75rem]", children: name }),
1442
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex flex-wrap items-center text-[1.25rem] text-white/90 max-[768px]:mb-[0.6rem] max-[768px]:text-[1.1rem] max-[480px]:mb-[0.5rem] max-[480px]:text-[1rem]", children: [
1443
+ /* @__PURE__ */ jsx("span", { children: location }),
1444
+ price == null ? null : /* @__PURE__ */ jsxs(
1445
+ "span",
1446
+ {
1447
+ className: "ml-4 flex items-center border-l border-white/30 pl-4 font-semibold",
1448
+ style: { color: "var(--color-accent, #e6c87e)" },
1449
+ children: [
1450
+ formatPrice2(price, currencySymbol),
1451
+ changePercent == null ? null : /* @__PURE__ */ jsxs(
1452
+ "span",
1453
+ {
1454
+ className: cn(
1455
+ "ml-2 flex items-center text-[0.875rem] font-medium",
1456
+ isPositive ? "text-[#0ecb81]" : "text-[#f6465d]"
1457
+ ),
1458
+ children: [
1459
+ /* @__PURE__ */ jsx(
1460
+ "svg",
1461
+ {
1462
+ xmlns: "http://www.w3.org/2000/svg",
1463
+ width: "12",
1464
+ height: "12",
1465
+ viewBox: "0 0 24 24",
1466
+ fill: "currentColor",
1467
+ className: "mr-[0.15rem]",
1468
+ children: /* @__PURE__ */ jsx("path", { d: isPositive ? "M7 14l5-5 5 5H7z" : "M7 10l5 5 5-5H7z" })
1469
+ }
1470
+ ),
1471
+ Math.abs(changePercent).toFixed(2),
1472
+ "%"
1473
+ ]
1474
+ }
1475
+ )
1476
+ ]
1477
+ }
1478
+ )
1479
+ ] }),
1480
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 text-[0.95rem] text-white/90 max-[768px]:hidden", children: [
1481
+ beds == null ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1482
+ /* @__PURE__ */ jsx(BedDouble, { className: "mr-2 h-[18px] w-[18px]" }),
1483
+ /* @__PURE__ */ jsxs("span", { children: [
1484
+ beds,
1485
+ " Beds"
1486
+ ] })
1487
+ ] }),
1488
+ baths == null ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1489
+ /* @__PURE__ */ jsx(Bath, { className: "mr-2 h-[18px] w-[18px]" }),
1490
+ /* @__PURE__ */ jsxs("span", { children: [
1491
+ baths,
1492
+ " Baths"
1493
+ ] })
1494
+ ] }),
1495
+ cars == null ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1496
+ /* @__PURE__ */ jsx(CarFront, { className: "mr-2 h-[18px] w-[18px]" }),
1497
+ /* @__PURE__ */ jsxs("span", { children: [
1498
+ cars,
1499
+ " Cars"
1500
+ ] })
1501
+ ] }),
1502
+ propertyTypeLabel == null ? null : /* @__PURE__ */ jsx("div", { children: propertyTypeLabel })
1503
+ ] })
1504
+ ] }),
1505
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 max-[768px]:w-full max-[768px]:flex-row max-[768px]:justify-between max-[768px]:gap-2 max-[480px]:gap-2", children: [
1506
+ /* @__PURE__ */ jsx(
1507
+ "button",
1508
+ {
1509
+ type: "button",
1510
+ onClick: onTrade,
1511
+ className: "rounded border border-transparent px-6 py-3 font-semibold transition-all hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] max-[768px]:flex-1 max-[768px]:px-5 max-[768px]:py-2.5 max-[768px]:text-[0.95rem] max-[480px]:px-4 max-[480px]:py-2 max-[480px]:text-[0.9rem]",
1512
+ style: { backgroundColor: "var(--color-accent, #e6c87e)", color: "black" },
1513
+ onMouseEnter: (e) => {
1514
+ e.currentTarget.style.backgroundColor = tradeHoverColor;
1515
+ },
1516
+ onMouseLeave: (e) => {
1517
+ e.currentTarget.style.backgroundColor = "var(--color-accent, #e6c87e)";
1518
+ },
1519
+ children: "Trade"
1520
+ }
1521
+ ),
1522
+ /* @__PURE__ */ jsx(
1523
+ "button",
1524
+ {
1525
+ type: "button",
1526
+ onClick: onMakeOffer,
1527
+ className: "rounded border px-6 py-3 font-semibold transition-all hover:-translate-y-0.5 hover:shadow-[0_4px_8px_rgba(0,0,0,0.2)] active:translate-y-0 active:shadow-[0_2px_4px_rgba(0,0,0,0.1)] max-[768px]:flex-1 max-[768px]:px-5 max-[768px]:py-2.5 max-[768px]:text-[0.95rem] max-[480px]:px-4 max-[480px]:py-2 max-[480px]:text-[0.9rem]",
1528
+ style: {
1529
+ backgroundColor: "transparent",
1530
+ borderColor: "var(--color-accent, #e6c87e)",
1531
+ color: "var(--color-accent, #e6c87e)"
1532
+ },
1533
+ onMouseEnter: (e) => {
1534
+ e.currentTarget.style.backgroundColor = "rgba(240, 185, 11, 0.1)";
1535
+ },
1536
+ onMouseLeave: (e) => {
1537
+ e.currentTarget.style.backgroundColor = "transparent";
1538
+ },
1539
+ children: "Make Offer"
1540
+ }
1541
+ )
1542
+ ] })
1543
+ ] })
1544
+ ]
1545
+ }
1546
+ );
1547
+ }
1548
+ );
1549
+ PropertyHeroHeader.displayName = "PropertyHeroHeader";
1550
+ var PropertySubheader = React5.forwardRef(
1551
+ ({ className, tabs, activeTabId, onTabChange, actions, ...props }, ref) => {
1552
+ return /* @__PURE__ */ jsxs(
1553
+ "div",
1554
+ {
1555
+ ref,
1556
+ className: cn(
1557
+ "w-full font-normal",
1558
+ "flex flex-col gap-3",
1559
+ "md:flex-row md:items-center md:justify-between",
1560
+ className
1561
+ ),
1562
+ ...props,
1563
+ children: [
1564
+ /* @__PURE__ */ jsx(
1565
+ "div",
1566
+ {
1567
+ className: cn(
1568
+ "flex items-center border-b border-white/10",
1569
+ "overflow-x-auto md:overflow-visible",
1570
+ "[-webkit-overflow-scrolling:touch]",
1571
+ "[scrollbar-width:none]",
1572
+ "[scroll-behavior:smooth]",
1573
+ "[touch-action:pan-x]",
1574
+ "md:border-b-0"
1575
+ ),
1576
+ style: { WebkitTapHighlightColor: "transparent" },
1577
+ children: /* @__PURE__ */ jsx("div", { className: "flex min-w-max", children: tabs.map((tab) => {
1578
+ const active = tab.id === activeTabId;
1579
+ return /* @__PURE__ */ jsxs(
1580
+ "button",
1581
+ {
1582
+ type: "button",
1583
+ onClick: () => onTabChange?.(tab.id),
1584
+ className: cn(
1585
+ "relative whitespace-nowrap",
1586
+ "px-6 py-4",
1587
+ "font-normal",
1588
+ "transition-colors",
1589
+ "max-[768px]:px-[1.2rem] max-[768px]:py-[0.8rem]",
1590
+ "max-[480px]:px-4 max-[480px]:py-[0.7rem] max-[480px]:text-[0.9rem]",
1591
+ active ? "font-semibold text-[var(--color-accent,#e6c87e)]" : "text-white/60 hover:text-white"
1592
+ ),
1593
+ style: {
1594
+ borderBottom: active ? "2px solid var(--color-accent, #e6c87e)" : "2px solid transparent",
1595
+ minWidth: "80px",
1596
+ touchAction: "manipulation"
1597
+ },
1598
+ children: [
1599
+ tab.label,
1600
+ tab.hasNotification ? /* @__PURE__ */ jsx(
1601
+ "span",
1602
+ {
1603
+ className: "absolute right-[10px] top-[10px] h-2 w-2 rounded-full animate-pulse",
1604
+ style: {
1605
+ backgroundColor: tab.notificationColor ?? "#f6465d",
1606
+ boxShadow: "0 0 0 0 rgba(246, 70, 93, 0.7)"
1607
+ }
1608
+ }
1609
+ ) : null
1610
+ ]
1611
+ },
1612
+ tab.id
1613
+ );
1614
+ }) })
1615
+ }
1616
+ ),
1617
+ actions != null && actions.length > 0 ? /* @__PURE__ */ jsx(
1618
+ "div",
1619
+ {
1620
+ className: cn(
1621
+ "flex items-center gap-[10px]",
1622
+ "overflow-x-auto md:overflow-visible",
1623
+ "[scrollbar-width:none]",
1624
+ "md:justify-end",
1625
+ "max-[768px]:w-full max-[768px]:justify-center max-[768px]:pb-2 max-[768px]:mb-4"
1626
+ ),
1627
+ children: actions.map((action) => /* @__PURE__ */ jsxs(
1628
+ "button",
1629
+ {
1630
+ type: "button",
1631
+ onClick: action.onClick,
1632
+ className: cn(
1633
+ "flex shrink-0 items-center gap-[5px] whitespace-nowrap",
1634
+ "rounded",
1635
+ "border border-white/10",
1636
+ "bg-transparent",
1637
+ "px-3 py-1.5 text-[14px] font-normal",
1638
+ "transition-all",
1639
+ "max-[768px]:px-2.5 max-[768px]:py-[5px] max-[768px]:text-[13px]",
1640
+ "hover:bg-white/5 hover:border-[var(--color-accent,#e6c87e)] hover:text-[var(--color-accent,#e6c87e)]"
1641
+ ),
1642
+ children: [
1643
+ action.icon,
1644
+ action.label
1645
+ ]
1646
+ },
1647
+ action.id
1648
+ ))
1649
+ }
1650
+ ) : null
1651
+ ]
1652
+ }
1653
+ );
1654
+ }
1655
+ );
1656
+ PropertySubheader.displayName = "PropertySubheader";
1657
+
1658
+ export { Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, HousePositionSlider, Orderbook, PortfolioSummary, PriceChart, PropertyHeroHeader, PropertyNewsUpdates, PropertySubheader, PropertyTour, YourOrders, badgeVariants, buttonVariants };
1659
+ //# sourceMappingURL=index.mjs.map
1660
+ //# sourceMappingURL=index.mjs.map