@loafmarkets/ui 0.1.263 → 0.1.264

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
@@ -12,7 +12,7 @@ import * as LightweightCharts from 'lightweight-charts';
12
12
  import { MdKingBed, MdBathtub, MdDirectionsCar, MdPool, MdYard, MdFitnessCenter } from 'react-icons/md';
13
13
  import { BiChevronUp, BiChevronDown, BiX, BiCoin, BiWallet, BiCreditCard, BiCalendar, BiInfoCircle, BiPencil, BiImages, BiVideo, BiMap } from 'react-icons/bi';
14
14
  import { FaChartLine, FaBitcoin } from 'react-icons/fa';
15
- import { FiEdit2 } from 'react-icons/fi';
15
+ import { FiChevronDown, FiEdit2 } from 'react-icons/fi';
16
16
 
17
17
  // src/components/button.tsx
18
18
  function cn(...inputs) {
@@ -13613,6 +13613,7 @@ function PortfolioActivityPanel({
13613
13613
  onCancelAllOrders,
13614
13614
  onAmendOrder,
13615
13615
  cancellingOrderId = null,
13616
+ compactPositions = false,
13616
13617
  defaultTab,
13617
13618
  pageSize = ACTIVITY_PAGE_SIZE_DEFAULT,
13618
13619
  blockExplorerBaseUrl = "https://sepolia.basescan.org/tx",
@@ -13637,6 +13638,41 @@ function PortfolioActivityPanel({
13637
13638
  setPosSortAsc(key === "asset");
13638
13639
  }
13639
13640
  };
13641
+ const [expandedPositions, setExpandedPositions] = useState(/* @__PURE__ */ new Set());
13642
+ const [allExpanded, setAllExpanded] = useState(false);
13643
+ const togglePosition = (tokenName) => {
13644
+ setExpandedPositions((prev) => {
13645
+ const next = new Set(prev);
13646
+ if (next.has(tokenName)) next.delete(tokenName);
13647
+ else next.add(tokenName);
13648
+ return next;
13649
+ });
13650
+ };
13651
+ const sortKeyLabel = (key) => {
13652
+ switch (key) {
13653
+ case "asset":
13654
+ return "Asset";
13655
+ case "units":
13656
+ return "Units";
13657
+ case "value":
13658
+ return "Value";
13659
+ case "avgPrice":
13660
+ return "Avg Price";
13661
+ case "currentPrice":
13662
+ return "Price";
13663
+ case "pnl":
13664
+ return "PNL";
13665
+ default:
13666
+ return "Asset";
13667
+ }
13668
+ };
13669
+ const sortKeys = ["asset", "units", "value", "avgPrice", "currentPrice", "pnl"];
13670
+ const cycleSortKey = () => {
13671
+ const idx = sortKeys.indexOf(posSortKey);
13672
+ const nextKey = sortKeys[(idx + 1) % sortKeys.length];
13673
+ setPosSortKey(nextKey);
13674
+ setPosSortAsc(true);
13675
+ };
13640
13676
  const sortedPositions = useMemo(() => {
13641
13677
  const arr = [...positions];
13642
13678
  const dir = posSortAsc ? 1 : -1;
@@ -13663,6 +13699,15 @@ function PortfolioActivityPanel({
13663
13699
  });
13664
13700
  return arr;
13665
13701
  }, [positions, posSortKey, posSortAsc]);
13702
+ const toggleExpandAll = () => {
13703
+ if (allExpanded) {
13704
+ setExpandedPositions(/* @__PURE__ */ new Set());
13705
+ setAllExpanded(false);
13706
+ } else {
13707
+ setExpandedPositions(new Set(sortedPositions.map((p) => p.tokenName)));
13708
+ setAllExpanded(true);
13709
+ }
13710
+ };
13666
13711
  const activeTabTotal = useMemo(() => {
13667
13712
  switch (activeTab) {
13668
13713
  case "positions":
@@ -13743,7 +13788,70 @@ function PortfolioActivityPanel({
13743
13788
  ] }),
13744
13789
  activeTab === "positions" && showPositionsTab && /* @__PURE__ */ jsxs(Fragment, { children: [
13745
13790
  positions.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "No positions yet. Subscribe to an offering or buy on the secondary market." }),
13746
- positions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
13791
+ positions.length > 0 && compactPositions && /* @__PURE__ */ jsxs(Fragment, { children: [
13792
+ /* @__PURE__ */ jsxs(CompactToolbar, { children: [
13793
+ /* @__PURE__ */ jsxs(CompactSortBtn, { onClick: cycleSortKey, children: [
13794
+ "Sort by: ",
13795
+ sortKeyLabel(posSortKey),
13796
+ " ",
13797
+ posSortAsc ? "\u2191" : "\u2193"
13798
+ ] }),
13799
+ /* @__PURE__ */ jsxs(CompactToolbarRight, { children: [
13800
+ /* @__PURE__ */ jsx(CompactActionBtn, { onClick: toggleExpandAll, children: allExpanded ? "Collapse All" : "Expand All" }),
13801
+ onClosePosition && /* @__PURE__ */ jsx(CompactSellAllBtn, { onClick: () => setCloseAllOpen(true), children: "Sell All" })
13802
+ ] })
13803
+ ] }),
13804
+ pageSlice(sortedPositions).map((pos) => {
13805
+ const currentValue = pos.quantity * pos.marketPrice;
13806
+ const costBasis = pos.quantity * pos.averageEntryPrice;
13807
+ const pnl = pos.propertyPnl ?? currentValue - costBasis;
13808
+ const pnlPercent = pos.propertyPnlPercent ?? pos.percentChange ?? 0;
13809
+ const isPositive = pnl >= 0;
13810
+ const isExpanded = expandedPositions.has(pos.tokenName);
13811
+ return /* @__PURE__ */ jsxs(CompactCard, { children: [
13812
+ /* @__PURE__ */ jsxs(CompactCardHeader, { onClick: () => togglePosition(pos.tokenName), children: [
13813
+ /* @__PURE__ */ jsx(CompactAsset, { onClick: (e) => {
13814
+ e.stopPropagation();
13815
+ onPositionClick?.(pos.tokenName, pos.isIpoAllocation);
13816
+ }, children: pos.tokenName }),
13817
+ /* @__PURE__ */ jsxs(CompactUnits, { children: [
13818
+ formatNumber2(pos.quantity),
13819
+ " units"
13820
+ ] }),
13821
+ /* @__PURE__ */ jsxs(CompactPnl, { $positive: isPositive, children: [
13822
+ isPositive ? "+" : "-",
13823
+ formatCurrency4(Math.abs(pnl)),
13824
+ " (",
13825
+ isPositive ? "+" : "",
13826
+ pnlPercent.toFixed(1),
13827
+ "%)"
13828
+ ] }),
13829
+ /* @__PURE__ */ jsx(CompactChevron, { $expanded: isExpanded, children: /* @__PURE__ */ jsx(FiChevronDown, { size: 14 }) })
13830
+ ] }),
13831
+ isExpanded && /* @__PURE__ */ jsxs(CompactCardBody, { children: [
13832
+ /* @__PURE__ */ jsxs(CompactDetailRow, { children: [
13833
+ /* @__PURE__ */ jsxs(CompactDetail, { children: [
13834
+ /* @__PURE__ */ jsx(CompactDetailLabel, { children: "Position Value" }),
13835
+ /* @__PURE__ */ jsx(CompactDetailValue, { children: formatCurrency4(currentValue, { minimumFractionDigits: 0, maximumFractionDigits: 0 }) })
13836
+ ] }),
13837
+ /* @__PURE__ */ jsxs(CompactDetail, { children: [
13838
+ /* @__PURE__ */ jsx(CompactDetailLabel, { children: "Avg Price" }),
13839
+ /* @__PURE__ */ jsx(CompactDetailValue, { children: formatCurrency4(pos.averageEntryPrice) })
13840
+ ] }),
13841
+ /* @__PURE__ */ jsxs(CompactDetail, { children: [
13842
+ /* @__PURE__ */ jsx(CompactDetailLabel, { children: "Current Price" }),
13843
+ /* @__PURE__ */ jsx(CompactDetailValue, { children: formatCurrency4(pos.marketPrice) })
13844
+ ] })
13845
+ ] }),
13846
+ onClosePosition && /* @__PURE__ */ jsxs(CompactCloseActions, { children: [
13847
+ /* @__PURE__ */ jsx(CloseBtn2, { onClick: () => onClosePosition(pos.tokenName, "market", pos.quantity, pos.marketPrice), children: "Market Sell" }),
13848
+ /* @__PURE__ */ jsx(CloseBtn2, { onClick: () => onClosePosition(pos.tokenName, "limit", pos.quantity, pos.marketPrice), children: "Limit Sell" })
13849
+ ] })
13850
+ ] })
13851
+ ] }, pos.tokenName);
13852
+ })
13853
+ ] }),
13854
+ positions.length > 0 && !compactPositions && /* @__PURE__ */ jsxs(Fragment, { children: [
13747
13855
  /* @__PURE__ */ jsxs(PositionsHeader, { $hasClose: !!onClosePosition, children: [
13748
13856
  /* @__PURE__ */ jsxs(SortableHeaderCell, { $active: posSortKey === "asset", onClick: () => handlePosSort("asset"), children: [
13749
13857
  "Asset ",
@@ -13813,29 +13921,29 @@ function PortfolioActivityPanel({
13813
13921
  }, children: "Limit Sell" })
13814
13922
  ] }) })
13815
13923
  ] }, pos.tokenName);
13816
- }),
13817
- closeAllOpen && onClosePosition && /* @__PURE__ */ jsx(CloseAllOverlay, { onClick: () => setCloseAllOpen(false), children: /* @__PURE__ */ jsxs(CloseAllModal, { onClick: (e) => e.stopPropagation(), children: [
13818
- /* @__PURE__ */ jsx(CloseAllModalX, { onClick: () => setCloseAllOpen(false), children: "\xD7" }),
13819
- /* @__PURE__ */ jsx(CloseAllTitle, { children: "Confirm Sell All" }),
13820
- /* @__PURE__ */ jsx(CloseAllDesc, { children: "This will sell all your positions and cancel their associated TP/SL orders." }),
13821
- /* @__PURE__ */ jsxs(CloseAllOption, { onClick: () => setCloseAllType("market"), children: [
13822
- /* @__PURE__ */ jsx(CloseAllRadio, { $selected: closeAllType === "market" }),
13823
- /* @__PURE__ */ jsx("span", { children: "Market Sell" })
13824
- ] }),
13825
- /* @__PURE__ */ jsxs(CloseAllOption, { onClick: () => setCloseAllType("limit"), children: [
13826
- /* @__PURE__ */ jsx(CloseAllRadio, { $selected: closeAllType === "limit" }),
13827
- /* @__PURE__ */ jsx("span", { children: "Limit Sell at Mid Price" })
13828
- ] }),
13829
- /* @__PURE__ */ jsxs(CloseAllConfirmBtn, { onClick: () => {
13830
- positions.forEach((pos) => onClosePosition(pos.tokenName, closeAllType, pos.quantity, pos.marketPrice));
13831
- setCloseAllOpen(false);
13832
- }, children: [
13833
- "Confirm ",
13834
- closeAllType === "market" ? "Market" : "Limit",
13835
- " Sell"
13836
- ] })
13837
- ] }) })
13838
- ] })
13924
+ })
13925
+ ] }),
13926
+ positions.length > 0 && closeAllOpen && onClosePosition && /* @__PURE__ */ jsx(CloseAllOverlay, { onClick: () => setCloseAllOpen(false), children: /* @__PURE__ */ jsxs(CloseAllModal, { onClick: (e) => e.stopPropagation(), children: [
13927
+ /* @__PURE__ */ jsx(CloseAllModalX, { onClick: () => setCloseAllOpen(false), children: "\xD7" }),
13928
+ /* @__PURE__ */ jsx(CloseAllTitle, { children: "Confirm Sell All" }),
13929
+ /* @__PURE__ */ jsx(CloseAllDesc, { children: "This will sell all your positions and cancel their associated TP/SL orders." }),
13930
+ /* @__PURE__ */ jsxs(CloseAllOption, { onClick: () => setCloseAllType("market"), children: [
13931
+ /* @__PURE__ */ jsx(CloseAllRadio, { $selected: closeAllType === "market" }),
13932
+ /* @__PURE__ */ jsx("span", { children: "Market Sell" })
13933
+ ] }),
13934
+ /* @__PURE__ */ jsxs(CloseAllOption, { onClick: () => setCloseAllType("limit"), children: [
13935
+ /* @__PURE__ */ jsx(CloseAllRadio, { $selected: closeAllType === "limit" }),
13936
+ /* @__PURE__ */ jsx("span", { children: "Limit Sell at Mid Price" })
13937
+ ] }),
13938
+ /* @__PURE__ */ jsxs(CloseAllConfirmBtn, { onClick: () => {
13939
+ positions.forEach((pos) => onClosePosition(pos.tokenName, closeAllType, pos.quantity, pos.marketPrice));
13940
+ setCloseAllOpen(false);
13941
+ }, children: [
13942
+ "Confirm ",
13943
+ closeAllType === "market" ? "Market" : "Limit",
13944
+ " Sell"
13945
+ ] })
13946
+ ] }) })
13839
13947
  ] }),
13840
13948
  activeTab === "subscriptions" && /* @__PURE__ */ jsxs(Fragment, { children: [
13841
13949
  offeringOrders.length === 0 && /* @__PURE__ */ jsx(EmptyState, { children: "IPO allocations will appear here once you subscribe." }),
@@ -14638,6 +14746,148 @@ var CloseAllConfirmBtn = styled9.button`
14638
14746
  background: rgba(246, 70, 93, 0.25);
14639
14747
  }
14640
14748
  `;
14749
+ var CompactToolbar = styled9.div`
14750
+ display: flex;
14751
+ align-items: center;
14752
+ justify-content: space-between;
14753
+ padding: 0.35rem 0.5rem;
14754
+ margin-bottom: 0.25rem;
14755
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
14756
+ `;
14757
+ var CompactSortBtn = styled9.button`
14758
+ background: transparent;
14759
+ border: 1px solid rgba(255, 255, 255, 0.1);
14760
+ border-radius: 4px;
14761
+ padding: 0.2rem 0.6rem;
14762
+ font-size: 0.68rem;
14763
+ font-weight: 500;
14764
+ color: rgba(255, 255, 255, 0.6);
14765
+ cursor: pointer;
14766
+ transition: all 0.15s ease;
14767
+
14768
+ &:hover {
14769
+ color: rgba(255, 255, 255, 0.85);
14770
+ border-color: rgba(255, 255, 255, 0.2);
14771
+ }
14772
+ `;
14773
+ var CompactToolbarRight = styled9.div`
14774
+ display: flex;
14775
+ align-items: center;
14776
+ gap: 0.4rem;
14777
+ `;
14778
+ var CompactActionBtn = styled9.button`
14779
+ background: transparent;
14780
+ border: 1px solid rgba(255, 255, 255, 0.1);
14781
+ border-radius: 4px;
14782
+ padding: 0.2rem 0.6rem;
14783
+ font-size: 0.68rem;
14784
+ font-weight: 500;
14785
+ color: rgba(255, 255, 255, 0.6);
14786
+ cursor: pointer;
14787
+ transition: all 0.15s ease;
14788
+
14789
+ &:hover {
14790
+ color: rgba(255, 255, 255, 0.85);
14791
+ border-color: rgba(255, 255, 255, 0.2);
14792
+ }
14793
+ `;
14794
+ var CompactSellAllBtn = styled9.button`
14795
+ background: rgba(246, 70, 93, 0.08);
14796
+ border: 1px solid rgba(246, 70, 93, 0.25);
14797
+ border-radius: 4px;
14798
+ padding: 0.2rem 0.6rem;
14799
+ font-size: 0.68rem;
14800
+ font-weight: 600;
14801
+ color: #f6465d;
14802
+ cursor: pointer;
14803
+ transition: all 0.15s ease;
14804
+
14805
+ &:hover {
14806
+ background: rgba(246, 70, 93, 0.15);
14807
+ border-color: rgba(246, 70, 93, 0.4);
14808
+ }
14809
+ `;
14810
+ var CompactCard = styled9.div`
14811
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
14812
+
14813
+ &:last-child {
14814
+ border-bottom: none;
14815
+ }
14816
+ `;
14817
+ var CompactCardHeader = styled9.div`
14818
+ display: grid;
14819
+ grid-template-columns: 1fr 1fr 1.4fr auto;
14820
+ align-items: center;
14821
+ gap: 0.5rem;
14822
+ padding: 0.6rem 0.5rem;
14823
+ cursor: pointer;
14824
+ transition: background 0.15s ease;
14825
+ border-radius: 4px;
14826
+
14827
+ &:hover {
14828
+ background: rgba(255, 255, 255, 0.03);
14829
+ }
14830
+ `;
14831
+ var CompactAsset = styled9.span`
14832
+ font-size: 0.8rem;
14833
+ font-weight: 600;
14834
+ color: #fff;
14835
+ cursor: pointer;
14836
+
14837
+ &:hover {
14838
+ text-decoration: underline;
14839
+ color: var(--color-accent, #E6C87E);
14840
+ }
14841
+ `;
14842
+ var CompactUnits = styled9.span`
14843
+ font-size: 0.75rem;
14844
+ color: rgba(255, 255, 255, 0.6);
14845
+ `;
14846
+ var CompactPnl = styled9.span`
14847
+ font-size: 0.75rem;
14848
+ font-weight: 600;
14849
+ color: ${(p) => p.$positive ? "#0ecb81" : "#f6465d"};
14850
+ text-align: right;
14851
+ `;
14852
+ var CompactChevron = styled9.span`
14853
+ display: flex;
14854
+ align-items: center;
14855
+ justify-content: center;
14856
+ color: rgba(255, 255, 255, 0.35);
14857
+ transition: transform 0.2s ease;
14858
+ transform: rotate(${(p) => p.$expanded ? "180deg" : "0deg"});
14859
+ `;
14860
+ var CompactCardBody = styled9.div`
14861
+ padding: 0 0.5rem 0.6rem;
14862
+ `;
14863
+ var CompactDetailRow = styled9.div`
14864
+ display: flex;
14865
+ gap: 1.5rem;
14866
+ padding: 0.5rem 0.75rem;
14867
+ background: rgba(255, 255, 255, 0.02);
14868
+ border-radius: 6px;
14869
+ margin-bottom: 0.5rem;
14870
+ `;
14871
+ var CompactDetail = styled9.div`
14872
+ display: flex;
14873
+ flex-direction: column;
14874
+ gap: 0.15rem;
14875
+ `;
14876
+ var CompactDetailLabel = styled9.span`
14877
+ font-size: 0.62rem;
14878
+ color: rgba(255, 255, 255, 0.35);
14879
+ font-weight: 500;
14880
+ `;
14881
+ var CompactDetailValue = styled9.span`
14882
+ font-size: 0.78rem;
14883
+ color: #fff;
14884
+ font-weight: 500;
14885
+ `;
14886
+ var CompactCloseActions = styled9.div`
14887
+ display: flex;
14888
+ gap: 0.5rem;
14889
+ padding: 0 0.75rem;
14890
+ `;
14641
14891
  function PropertyBuy({
14642
14892
  propertyName = "Loaf Property",
14643
14893
  propertyLocation: propertyLocationLabel = "Sydney, NSW",