@loafmarkets/ui 0.1.144 → 0.1.146

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 CHANGED
@@ -8297,7 +8297,10 @@ function PropertyOverview({
8297
8297
  ticker,
8298
8298
  contractAddress,
8299
8299
  chain = "Base (Ethereum L2)",
8300
- percentageTokenized
8300
+ percentageTokenized,
8301
+ volume24h,
8302
+ openOrdersValue,
8303
+ holderCount
8301
8304
  }) {
8302
8305
  const [isDescExpanded, setDescExpanded] = useState(false);
8303
8306
  const description = descriptionProp ?? overviewData?.description ?? DEFAULT_DESCRIPTION;
@@ -8334,7 +8337,7 @@ function PropertyOverview({
8334
8337
  const tokenPriceValue = midPrice > 0 ? midPrice : null;
8335
8338
  const weeklyRent = overviewData?.weeklyRent ?? 0;
8336
8339
  const annualRent = weeklyRent * 52;
8337
- const dividendYield = resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
8340
+ resolvedValuation && annualRent > 0 ? (annualRent / resolvedValuation * 100).toFixed(2) : null;
8338
8341
  const monthlyCoupon = annualRent / 12;
8339
8342
  const tokenMarketCap = tokenPriceValue && resolvedTokensIssued ? tokenPriceValue * resolvedTokensIssued : null;
8340
8343
  const currentDividendYield = tokenMarketCap && monthlyCoupon > 0 ? (monthlyCoupon * 12 / tokenMarketCap * 100).toFixed(2) : null;
@@ -8350,17 +8353,27 @@ function PropertyOverview({
8350
8353
  { label: "Property Type", value: resolvedPropertyType ?? "\u2014" },
8351
8354
  { label: "Location", value: location || "\u2014" }
8352
8355
  ];
8356
+ const vol24hDollar = volume24h != null && tokenPriceValue ? volume24h * tokenPriceValue : null;
8357
+ const holdRatio = (() => {
8358
+ if (!tokenMarketCap || tokenMarketCap <= 0 || vol24hDollar == null) return null;
8359
+ const turnover = vol24hDollar / (tokenMarketCap / 2);
8360
+ const holdPct = Math.max(0, Math.min(100, (1 - turnover) * 100));
8361
+ return { holdPct, tradePct: +(100 - holdPct).toFixed(1) };
8362
+ })();
8353
8363
  const tokenStats = [
8354
8364
  { label: "Token Price", value: isLoading && tokenPriceValue == null ? loadingSkeleton : tokenPriceValue ? `$${tokenPriceValue.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "\u2014", gold: true },
8355
- { label: "Property Value", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "\u2014" },
8356
- { label: "Dividend Yield", value: isLoading && dividendYield == null ? loadingSkeleton : dividendYield ? `${dividendYield}%` : "\u2014" },
8357
- { label: "Total Tokens", value: isLoading && resolvedTokensIssued == null ? loadingSkeleton : resolvedTokensIssued?.toLocaleString() ?? "\u2014" }
8365
+ { label: "24h Volume", value: isLoading && vol24hDollar == null ? loadingSkeleton : vol24hDollar != null && vol24hDollar > 0 ? `$${Math.round(vol24hDollar).toLocaleString()}` : "\u2014" },
8366
+ { label: "Current Dividend Yield", value: isLoading && currentDividendYield == null ? loadingSkeleton : currentDividendYield ? `${currentDividendYield}%` : "\u2014" },
8367
+ { label: "Open Orders", value: isLoading && openOrdersValue == null ? loadingSkeleton : openOrdersValue != null && openOrdersValue > 0 ? `$${Math.round(openOrdersValue).toLocaleString()}` : "\u2014" },
8368
+ { label: "Holders", value: isLoading && holderCount == null ? loadingSkeleton : holderCount != null ? holderCount.toLocaleString() : "\u2014" }
8358
8369
  ];
8370
+ const cashFlowPerShare = annualRent > 0 && resolvedTokensIssued ? annualRent / resolvedTokensIssued : null;
8359
8371
  const propertyStats = [
8360
- { label: "Offering Valuation", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "\u2014" },
8361
- { label: "Current Dividend Yield", value: isLoading && currentDividendYield == null ? loadingSkeleton : currentDividendYield ? `${currentDividendYield}%` : "\u2014" },
8362
- { label: "Annual Rent", value: isLoading && !overviewData ? loadingSkeleton : annualRent > 0 ? `$${annualRent.toLocaleString()}/yr` : "\u2014" },
8363
- { label: "Year Built", value: isLoading && !overviewData ? loadingSkeleton : overviewData?.yearBuilt ? String(overviewData.yearBuilt) : "\u2014" }
8372
+ { label: "Last Valuation", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "\u2014" },
8373
+ { label: "Number of Offers", value: "\u2014" },
8374
+ { label: "Growth (Past 5 Years)", value: "\u2014" },
8375
+ { label: "Security Interest in Asset", value: "Yes, secured to Land Registry" },
8376
+ { label: "Cash Flow Per Share", value: isLoading && cashFlowPerShare == null ? loadingSkeleton : cashFlowPerShare != null ? `$${cashFlowPerShare.toFixed(4)}/yr` : "\u2014" }
8364
8377
  ];
8365
8378
  return /* @__PURE__ */ jsxs(Wrapper, { children: [
8366
8379
  /* @__PURE__ */ jsxs(Section, { children: [
@@ -8393,7 +8406,30 @@ function PropertyOverview({
8393
8406
  tokenStats.map((item) => /* @__PURE__ */ jsxs(StatRow, { $gold: !!item.gold, children: [
8394
8407
  /* @__PURE__ */ jsx(StatLabel, { children: item.label }),
8395
8408
  /* @__PURE__ */ jsx(StatValue, { $gold: !!item.gold, children: item.value })
8396
- ] }, item.label))
8409
+ ] }, item.label)),
8410
+ holdRatio && /* @__PURE__ */ jsxs(HoldRatioWrap, { children: [
8411
+ /* @__PURE__ */ jsxs(HoldRatioTitle, { children: [
8412
+ /* @__PURE__ */ jsx(HoldRatioTitleText, { children: "Holding Ratio" }),
8413
+ /* @__PURE__ */ jsx(HoldRatioInfo, { "data-tip": "Proportion of token holders vs active traders over the last 24 hours, measured by trading volume against market capitalisation.", children: "?" })
8414
+ ] }),
8415
+ /* @__PURE__ */ jsxs(HoldRatioHeader, { children: [
8416
+ /* @__PURE__ */ jsxs("div", { children: [
8417
+ /* @__PURE__ */ jsx(HoldRatioLabel, { $side: "hold", children: "Holding " }),
8418
+ /* @__PURE__ */ jsxs(HoldRatioValue, { $side: "hold", children: [
8419
+ holdRatio.holdPct.toFixed(1),
8420
+ "%"
8421
+ ] })
8422
+ ] }),
8423
+ /* @__PURE__ */ jsxs("div", { children: [
8424
+ /* @__PURE__ */ jsxs(HoldRatioValue, { $side: "trade", children: [
8425
+ holdRatio.tradePct,
8426
+ "%"
8427
+ ] }),
8428
+ /* @__PURE__ */ jsx(HoldRatioLabel, { $side: "trade", children: " Trading" })
8429
+ ] })
8430
+ ] }),
8431
+ /* @__PURE__ */ jsx(HoldRatioTrack, { children: /* @__PURE__ */ jsx(HoldRatioFill, { $pct: holdRatio.holdPct }) })
8432
+ ] })
8397
8433
  ] }),
8398
8434
  /* @__PURE__ */ jsxs(StatsColumn, { children: [
8399
8435
  /* @__PURE__ */ jsx(StatsColumnHeader, { children: "Property Fundamentals" }),
@@ -8782,6 +8818,101 @@ var ProtectionDesc = styled19.div`
8782
8818
  color: rgba(255,255,255,0.5);
8783
8819
  line-height: 1.5;
8784
8820
  `;
8821
+ var HoldRatioWrap = styled19.div`
8822
+ display: flex;
8823
+ flex-direction: column;
8824
+ gap: 6px;
8825
+ padding: 0.75rem 0 0;
8826
+ margin-top: 0.5rem;
8827
+ border-top: 1px solid rgba(255,255,255,0.04);
8828
+ `;
8829
+ var HoldRatioTitle = styled19.div`
8830
+ display: flex;
8831
+ align-items: center;
8832
+ gap: 5px;
8833
+ `;
8834
+ var HoldRatioTitleText = styled19.span`
8835
+ font-size: 0.65rem;
8836
+ font-weight: 600;
8837
+ text-transform: uppercase;
8838
+ letter-spacing: 0.06em;
8839
+ color: rgba(255,255,255,0.4);
8840
+ `;
8841
+ var HoldRatioInfo = styled19.span`
8842
+ position: relative;
8843
+ display: inline-flex;
8844
+ align-items: center;
8845
+ justify-content: center;
8846
+ width: 13px;
8847
+ height: 13px;
8848
+ border-radius: 50%;
8849
+ border: 1px solid rgba(255,255,255,0.15);
8850
+ font-size: 0.5rem;
8851
+ font-weight: 700;
8852
+ color: rgba(255,255,255,0.3);
8853
+ cursor: help;
8854
+ flex-shrink: 0;
8855
+
8856
+ &::after {
8857
+ content: attr(data-tip);
8858
+ position: absolute;
8859
+ bottom: calc(100% + 6px);
8860
+ left: 0;
8861
+ width: max-content;
8862
+ max-width: 260px;
8863
+ padding: 8px 12px;
8864
+ border-radius: 6px;
8865
+ background: #1a1a1e;
8866
+ border: 1px solid rgba(255,255,255,0.1);
8867
+ color: rgba(255,255,255,0.7);
8868
+ font-size: 0.7rem;
8869
+ font-weight: 400;
8870
+ letter-spacing: 0;
8871
+ text-transform: none;
8872
+ line-height: 1.45;
8873
+ white-space: normal;
8874
+ pointer-events: none;
8875
+ opacity: 0;
8876
+ transition: opacity 0.15s;
8877
+ z-index: 10;
8878
+ }
8879
+
8880
+ &:hover::after {
8881
+ opacity: 1;
8882
+ }
8883
+ `;
8884
+ var HoldRatioHeader = styled19.div`
8885
+ display: flex;
8886
+ align-items: center;
8887
+ justify-content: space-between;
8888
+ `;
8889
+ var HoldRatioLabel = styled19.span`
8890
+ font-size: 0.7rem;
8891
+ font-weight: 600;
8892
+ text-transform: uppercase;
8893
+ letter-spacing: 0.05em;
8894
+ color: ${(p) => p.$side === "trade" ? "rgba(246, 70, 93, 0.6)" : "rgba(14, 203, 129, 0.6)"};
8895
+ `;
8896
+ var HoldRatioValue = styled19.span`
8897
+ font-size: 0.75rem;
8898
+ font-weight: 600;
8899
+ font-variant-numeric: tabular-nums;
8900
+ color: ${(p) => p.$side === "trade" ? "rgba(246, 70, 93, 0.7)" : "rgba(14, 203, 129, 0.7)"};
8901
+ `;
8902
+ var HoldRatioTrack = styled19.div`
8903
+ height: 6px;
8904
+ border-radius: 3px;
8905
+ background: rgba(246, 70, 93, 0.15);
8906
+ overflow: hidden;
8907
+ position: relative;
8908
+ `;
8909
+ var HoldRatioFill = styled19.div`
8910
+ height: 100%;
8911
+ width: ${(p) => p.$pct}%;
8912
+ border-radius: 3px;
8913
+ background: rgba(14, 203, 129, 0.35);
8914
+ transition: width 0.6s ease;
8915
+ `;
8785
8916
  var STATUS_BG = {
8786
8917
  active: "rgba(14,203,129,0.18)",
8787
8918
  rejected: "rgba(246,70,93,0.18)",