@loafmarkets/ui 0.1.144 → 0.1.145

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,11 +8353,19 @@ 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
  ];
8359
8370
  const propertyStats = [
8360
8371
  { label: "Offering Valuation", value: isLoading && resolvedValuation == null ? loadingSkeleton : resolvedValuation ? resolvedValuation >= 1e6 ? `$${(resolvedValuation / 1e6).toFixed(2)}M` : `$${resolvedValuation.toLocaleString()}` : "\u2014" },
@@ -8393,7 +8404,30 @@ function PropertyOverview({
8393
8404
  tokenStats.map((item) => /* @__PURE__ */ jsxs(StatRow, { $gold: !!item.gold, children: [
8394
8405
  /* @__PURE__ */ jsx(StatLabel, { children: item.label }),
8395
8406
  /* @__PURE__ */ jsx(StatValue, { $gold: !!item.gold, children: item.value })
8396
- ] }, item.label))
8407
+ ] }, item.label)),
8408
+ holdRatio && /* @__PURE__ */ jsxs(HoldRatioWrap, { children: [
8409
+ /* @__PURE__ */ jsxs(HoldRatioTitle, { children: [
8410
+ /* @__PURE__ */ jsx(HoldRatioTitleText, { children: "Holding Ratio" }),
8411
+ /* @__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: "?" })
8412
+ ] }),
8413
+ /* @__PURE__ */ jsxs(HoldRatioHeader, { children: [
8414
+ /* @__PURE__ */ jsxs("div", { children: [
8415
+ /* @__PURE__ */ jsx(HoldRatioLabel, { $side: "hold", children: "Holding " }),
8416
+ /* @__PURE__ */ jsxs(HoldRatioValue, { $side: "hold", children: [
8417
+ holdRatio.holdPct.toFixed(1),
8418
+ "%"
8419
+ ] })
8420
+ ] }),
8421
+ /* @__PURE__ */ jsxs("div", { children: [
8422
+ /* @__PURE__ */ jsxs(HoldRatioValue, { $side: "trade", children: [
8423
+ holdRatio.tradePct,
8424
+ "%"
8425
+ ] }),
8426
+ /* @__PURE__ */ jsx(HoldRatioLabel, { $side: "trade", children: " Trading" })
8427
+ ] })
8428
+ ] }),
8429
+ /* @__PURE__ */ jsx(HoldRatioTrack, { children: /* @__PURE__ */ jsx(HoldRatioFill, { $pct: holdRatio.holdPct }) })
8430
+ ] })
8397
8431
  ] }),
8398
8432
  /* @__PURE__ */ jsxs(StatsColumn, { children: [
8399
8433
  /* @__PURE__ */ jsx(StatsColumnHeader, { children: "Property Fundamentals" }),
@@ -8782,6 +8816,101 @@ var ProtectionDesc = styled19.div`
8782
8816
  color: rgba(255,255,255,0.5);
8783
8817
  line-height: 1.5;
8784
8818
  `;
8819
+ var HoldRatioWrap = styled19.div`
8820
+ display: flex;
8821
+ flex-direction: column;
8822
+ gap: 6px;
8823
+ padding: 0.75rem 0 0;
8824
+ margin-top: 0.5rem;
8825
+ border-top: 1px solid rgba(255,255,255,0.04);
8826
+ `;
8827
+ var HoldRatioTitle = styled19.div`
8828
+ display: flex;
8829
+ align-items: center;
8830
+ gap: 5px;
8831
+ `;
8832
+ var HoldRatioTitleText = styled19.span`
8833
+ font-size: 0.65rem;
8834
+ font-weight: 600;
8835
+ text-transform: uppercase;
8836
+ letter-spacing: 0.06em;
8837
+ color: rgba(255,255,255,0.4);
8838
+ `;
8839
+ var HoldRatioInfo = styled19.span`
8840
+ position: relative;
8841
+ display: inline-flex;
8842
+ align-items: center;
8843
+ justify-content: center;
8844
+ width: 13px;
8845
+ height: 13px;
8846
+ border-radius: 50%;
8847
+ border: 1px solid rgba(255,255,255,0.15);
8848
+ font-size: 0.5rem;
8849
+ font-weight: 700;
8850
+ color: rgba(255,255,255,0.3);
8851
+ cursor: help;
8852
+ flex-shrink: 0;
8853
+
8854
+ &::after {
8855
+ content: attr(data-tip);
8856
+ position: absolute;
8857
+ bottom: calc(100% + 6px);
8858
+ left: 0;
8859
+ width: max-content;
8860
+ max-width: 260px;
8861
+ padding: 8px 12px;
8862
+ border-radius: 6px;
8863
+ background: #1a1a1e;
8864
+ border: 1px solid rgba(255,255,255,0.1);
8865
+ color: rgba(255,255,255,0.7);
8866
+ font-size: 0.7rem;
8867
+ font-weight: 400;
8868
+ letter-spacing: 0;
8869
+ text-transform: none;
8870
+ line-height: 1.45;
8871
+ white-space: normal;
8872
+ pointer-events: none;
8873
+ opacity: 0;
8874
+ transition: opacity 0.15s;
8875
+ z-index: 10;
8876
+ }
8877
+
8878
+ &:hover::after {
8879
+ opacity: 1;
8880
+ }
8881
+ `;
8882
+ var HoldRatioHeader = styled19.div`
8883
+ display: flex;
8884
+ align-items: center;
8885
+ justify-content: space-between;
8886
+ `;
8887
+ var HoldRatioLabel = styled19.span`
8888
+ font-size: 0.7rem;
8889
+ font-weight: 600;
8890
+ text-transform: uppercase;
8891
+ letter-spacing: 0.05em;
8892
+ color: ${(p) => p.$side === "trade" ? "rgba(246, 70, 93, 0.6)" : "rgba(14, 203, 129, 0.6)"};
8893
+ `;
8894
+ var HoldRatioValue = styled19.span`
8895
+ font-size: 0.75rem;
8896
+ font-weight: 600;
8897
+ font-variant-numeric: tabular-nums;
8898
+ color: ${(p) => p.$side === "trade" ? "rgba(246, 70, 93, 0.7)" : "rgba(14, 203, 129, 0.7)"};
8899
+ `;
8900
+ var HoldRatioTrack = styled19.div`
8901
+ height: 6px;
8902
+ border-radius: 3px;
8903
+ background: rgba(246, 70, 93, 0.15);
8904
+ overflow: hidden;
8905
+ position: relative;
8906
+ `;
8907
+ var HoldRatioFill = styled19.div`
8908
+ height: 100%;
8909
+ width: ${(p) => p.$pct}%;
8910
+ border-radius: 3px;
8911
+ background: rgba(14, 203, 129, 0.35);
8912
+ transition: width 0.6s ease;
8913
+ `;
8785
8914
  var STATUS_BG = {
8786
8915
  active: "rgba(14,203,129,0.18)",
8787
8916
  rejected: "rgba(246,70,93,0.18)",