{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "crypto-wallet-portfolio",
  "title": "Crypto Wallet Portfolio",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/crypto-wallet-portfolio/crypto-wallet-portfolio.component.ts",
      "content": "// Coinbase / Phantom-style multi-asset crypto holdings dashboard: treasury header\n// with address copy and network badge, portfolio balance hero with 24h PnL and a\n// multi-asset allocation bar, an asset holdings table, and an interactive quick\n// swap calculator. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core'\nimport {\n  ArrowDownLeft,\n  ArrowDownUp,\n  ArrowLeftRight,\n  ArrowUpRight,\n  Check,\n  Copy,\n  Fuel,\n  LucideAngularModule,\n  RefreshCw,\n  ShieldCheck,\n  TrendingDown,\n  TrendingUp,\n  Wallet,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport interface CryptoAsset {\n  id: string\n  name: string\n  symbol: string\n  price: string\n  rawPrice: number\n  change24h: string\n  isPositive: boolean\n  balance: string\n  rawBalance: number\n  fiatValue: string\n  allocation: string\n  color: string\n}\n\nexport const cryptoAssets: CryptoAsset[] = [\n  {\n    id: 'eth',\n    name: 'Ethereum',\n    symbol: 'ETH',\n    price: '$3,450.00',\n    rawPrice: 3450.0,\n    change24h: '+3.2%',\n    isPositive: true,\n    balance: '24.5 ETH',\n    rawBalance: 24.5,\n    fiatValue: '$84,525.00',\n    allocation: '56.8%',\n    color: '#627EEA',\n  },\n  {\n    id: 'btc',\n    name: 'Bitcoin',\n    symbol: 'BTC',\n    price: '$64,200.00',\n    rawPrice: 64200.0,\n    change24h: '+1.8%',\n    isPositive: true,\n    balance: '0.58 BTC',\n    rawBalance: 0.58,\n    fiatValue: '$37,236.00',\n    allocation: '25.0%',\n    color: '#F7931A',\n  },\n  {\n    id: 'sol',\n    name: 'Solana',\n    symbol: 'SOL',\n    price: '$148.50',\n    rawPrice: 148.5,\n    change24h: '-1.1%',\n    isPositive: false,\n    balance: '120.4 SOL',\n    rawBalance: 120.4,\n    fiatValue: '$17,879.40',\n    allocation: '12.0%',\n    color: '#14F195',\n  },\n  {\n    id: 'usdc',\n    name: 'USD Coin',\n    symbol: 'USDC',\n    price: '$1.00',\n    rawPrice: 1.0,\n    change24h: '+0.01%',\n    isPositive: true,\n    balance: '7,450.00 USDC',\n    rawBalance: 7450.0,\n    fiatValue: '$7,450.00',\n    allocation: '5.0%',\n    color: '#2775CA',\n  },\n  {\n    id: 'link',\n    name: 'Chainlink',\n    symbol: 'LINK',\n    price: '$18.30',\n    rawPrice: 18.3,\n    change24h: '+5.4%',\n    isPositive: true,\n    balance: '100.0 LINK',\n    rawBalance: 100.0,\n    fiatValue: '$1,830.10',\n    allocation: '1.2%',\n    color: '#375BD2',\n  },\n]\n\nexport const walletFullAddress = '0x71C856402244243b92834b9d09c2534575823a9F'\nexport const walletShortAddress = '0x71C...3a9F'\n\nconst slippageOptions = ['0.1', '0.5', '1.0']\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-crypto-wallet-portfolio, [ui-crypto-wallet-portfolio]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiInputComponent,\n    UiSeparatorComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"crypto-wallet-portfolio\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <header class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1.5\">\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <div\n              class=\"bg-primary/10 text-primary border-primary/20 flex size-9 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n              aria-hidden=\"true\"\n            >\n              <lucide-icon [img]=\"Wallet\" class=\"size-5\" />\n            </div>\n            <h1 class=\"text-foreground text-2xl font-bold tracking-tight\">Main Treasury Vault</h1>\n            <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1.5 font-normal\">\n              <span class=\"bg-success size-1.5 animate-pulse rounded-full\" aria-hidden=\"true\"></span>\n              Ethereum Mainnet\n            </span>\n          </div>\n\n          <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 text-xs\">\n            <span class=\"bg-muted/70 text-foreground border-border/80 rounded border px-2 py-0.5 font-mono font-medium\">\n              {{ shortAddress }}\n            </span>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"icon-sm\"\n              class=\"text-muted-foreground hover:text-foreground size-6\"\n              aria-label=\"Copy wallet address\"\n              (click)=\"copyAddress()\"\n            >\n              @if (copied()) {\n                <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"Copy\" class=\"size-3.5\" />\n              }\n            </button>\n            <span class=\"inline-flex items-center gap-1\">\n              <lucide-icon [img]=\"ShieldCheck\" class=\"text-primary size-3.5\" />\n              Multi-Sig (3 of 5)\n            </span>\n          </div>\n        </div>\n\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <button ui-button variant=\"outline\" size=\"sm\" class=\"gap-1.5 shadow-xs\">\n            <lucide-icon [img]=\"ArrowUpRight\" class=\"size-4\" />\n            Send\n          </button>\n          <button ui-button variant=\"outline\" size=\"sm\" class=\"gap-1.5 shadow-xs\">\n            <lucide-icon [img]=\"ArrowDownLeft\" class=\"size-4\" />\n            Receive\n          </button>\n          <button ui-button size=\"sm\" class=\"gap-1.5 shadow-xs\">\n            <lucide-icon [img]=\"ArrowLeftRight\" class=\"size-4\" />\n            Swap\n          </button>\n        </div>\n      </header>\n\n      <!-- Main Grid: Portfolio Overview + Holdings Table & Quick Swap Calculator -->\n      <div class=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n        <!-- Left Column: Hero Portfolio Card & Holdings Table (8 cols) -->\n        <div class=\"space-y-6 lg:col-span-8\">\n          <!-- Hero Portfolio Balance Card -->\n          <div ui-card class=\"border-border overflow-hidden shadow-xs\">\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex items-center justify-between\">\n                <p ui-card-description class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                  Total Portfolio Value\n                </p>\n                <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n                  <span class=\"bg-success size-2 rounded-full\" aria-hidden=\"true\"></span>\n                  Live Oracle Feed\n                </div>\n              </div>\n              <div class=\"mt-2 flex flex-wrap items-baseline gap-3\">\n                <span class=\"text-foreground text-3xl font-bold tracking-tight tabular-nums sm:text-4xl\">\n                  $148,920.50\n                </span>\n                <div\n                  class=\"border-success/20 bg-success/10 text-success text-success inline-flex items-center gap-1 rounded-full border px-2.5 py-0.5 text-xs font-semibold tabular-nums\"\n                >\n                  <lucide-icon [img]=\"TrendingUp\" class=\"size-3.5\" />\n                  +$6,420.10 (+4.51%)\n                  <span class=\"text-muted-foreground ml-0.5 font-normal\">24h</span>\n                </div>\n              </div>\n            </div>\n            <div ui-card-content class=\"space-y-4 pt-1\">\n              <!-- Stacked Allocation Bar -->\n              <div class=\"space-y-2\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <span class=\"text-foreground font-medium\">Asset Allocation</span>\n                  <span class=\"tabular-nums\">5 Assets</span>\n                </div>\n                <div\n                  class=\"bg-muted/60 border-border/50 flex h-3 w-full gap-0.5 overflow-hidden rounded-full border p-0.5\"\n                >\n                  @for (asset of assets; track asset.id) {\n                    <div\n                      [style.width]=\"asset.allocation\"\n                      [style.backgroundColor]=\"asset.color\"\n                      class=\"h-full transition-opacity duration-300 first:rounded-l-full last:rounded-r-full hover:opacity-90\"\n                      [attr.title]=\"asset.name + ' (' + asset.symbol + '): ' + asset.allocation\"\n                    ></div>\n                  }\n                </div>\n\n                <!-- Allocation Legend -->\n                <div class=\"flex flex-wrap items-center gap-x-4 gap-y-2 pt-1 text-xs\">\n                  @for (asset of assets; track asset.id) {\n                    <div class=\"flex items-center gap-1.5\">\n                      <span\n                        class=\"size-2.5 shrink-0 rounded-full shadow-xs\"\n                        [style.backgroundColor]=\"asset.color\"\n                        aria-hidden=\"true\"\n                      ></span>\n                      <span class=\"text-foreground font-medium\">{{ asset.symbol }}</span>\n                      <span class=\"text-muted-foreground tabular-nums\">{{ asset.allocation }}</span>\n                    </div>\n                  }\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Asset Holdings Table Card -->\n          <div ui-card class=\"border-border shadow-xs\">\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex items-center justify-between\">\n                <div>\n                  <h3 ui-card-title class=\"text-foreground text-base font-semibold\">Asset Holdings</h3>\n                  <p ui-card-description class=\"text-muted-foreground text-xs\">\n                    Real-time token prices, balances, and portfolio share.\n                  </p>\n                </div>\n                <span ui-badge variant=\"secondary\" class=\"text-xs font-normal tabular-nums\"> 5 Assets </span>\n              </div>\n            </div>\n            <div ui-card-content class=\"p-0\">\n              <div class=\"overflow-x-auto\">\n                <table ui-table>\n                  <thead ui-table-header>\n                    <tr ui-table-row>\n                      <th ui-table-head class=\"pl-6\">Asset</th>\n                      <th ui-table-head class=\"text-right\">Price (24h)</th>\n                      <th ui-table-head class=\"text-right\">Holdings</th>\n                      <th ui-table-head class=\"hidden text-right sm:table-cell\">Portfolio Share</th>\n                      <th ui-table-head class=\"pr-6 text-right\">Actions</th>\n                    </tr>\n                  </thead>\n                  <tbody ui-table-body>\n                    @for (asset of assets; track asset.id) {\n                      <tr ui-table-row class=\"hover:bg-muted/40 transition-colors\">\n                        <!-- Token Icon, Name, Symbol -->\n                        <td ui-table-cell class=\"py-3.5 pl-6\">\n                          <div class=\"flex items-center gap-3\">\n                            @if (asset.id === 'eth') {\n                              <svg\n                                viewBox=\"0 0 32 32\"\n                                class=\"size-8 shrink-0 rounded-full shadow-xs\"\n                                aria-hidden=\"true\"\n                              >\n                                <circle cx=\"16\" cy=\"16\" r=\"16\" fill=\"#627EEA\" />\n                                <path fill=\"#ffffff\" fill-opacity=\"0.6\" d=\"M16.5 4v8.87l7.5 3.35z\" />\n                                <path fill=\"#ffffff\" d=\"M16.5 4L9 16.22l7.5-3.35z\" />\n                                <path fill=\"#ffffff\" fill-opacity=\"0.6\" d=\"M16.5 21.97v6.03L24 17.62z\" />\n                                <path fill=\"#ffffff\" d=\"M16.5 28v-6.03L9 17.62z\" />\n                                <path fill=\"#ffffff\" fill-opacity=\"0.2\" d=\"M16.5 20.57l7.5-4.35-7.5-3.35z\" />\n                                <path fill=\"#ffffff\" fill-opacity=\"0.6\" d=\"M9 16.22l7.5 4.35v-7.7z\" />\n                              </svg>\n                            } @else if (asset.id === 'btc') {\n                              <svg\n                                viewBox=\"0 0 32 32\"\n                                class=\"size-8 shrink-0 rounded-full shadow-xs\"\n                                aria-hidden=\"true\"\n                              >\n                                <circle cx=\"16\" cy=\"16\" r=\"16\" fill=\"#F7931A\" />\n                                <path\n                                  fill=\"#ffffff\"\n                                  d=\"M22.5 13.5c.3-1.9-1.2-2.9-3.2-3.6l.7-2.6-1.6-.4-.6 2.5c-.4-.1-.9-.2-1.3-.3l.6-2.5-1.6-.4-.7 2.6c-.3-.1-.7-.2-1-.2l-2.2-.5-.4 1.7s.9.2.9.2c.5.1.6.4.6.6l-.6 2.5c0 0 .1 0 .2 0l-.2 0-.9 3.5c-.1.2-.3.4-.6.3 0 0-.9-.2-.9-.2l-.8 1.8 2.1.5c.4.1.8.2 1.2.3l-.7 2.7 1.6.4.7-2.6c.4.1.9.2 1.3.3l-.7 2.7 1.6.4.7-2.7c2.8.5 4.8.3 5.7-2.2.7-2-.1-3.1-1.5-3.8 1.1-.3 1.8-1 2-2.5zm-3.6 5.4c-.5 2-3.9.9-5 .6l.9-3.6c1.1.3 4.6.8 4.1 3zm.5-5.6c-.5 1.8-3.3.9-4.2.7l.8-3.3c.9.2 3.8.7 3.4 2.6z\"\n                                />\n                              </svg>\n                            } @else if (asset.id === 'sol') {\n                              <svg\n                                viewBox=\"0 0 32 32\"\n                                class=\"size-8 shrink-0 rounded-full shadow-xs\"\n                                aria-hidden=\"true\"\n                              >\n                                <circle cx=\"16\" cy=\"16\" r=\"16\" fill=\"#14151a\" />\n                                <path\n                                  fill=\"#14F195\"\n                                  d=\"M8.5 21.8l1.8-1.8c.3-.3.7-.5 1.1-.5h10.4c.5 0 .9.6.6 1l-1.8 1.8c-.3.3-.7.5-1.1.5H9.1c-.5 0-.9-.6-.6-1z\"\n                                />\n                                <path\n                                  fill=\"#9945FF\"\n                                  d=\"M8.5 12.8l1.8-1.8c.3-.3.7-.5 1.1-.5h10.4c.5 0 .9.6.6 1l-1.8 1.8c-.3.3-.7.5-1.1.5H9.1c-.5 0-.9-.6-.6-1z\"\n                                />\n                                <path\n                                  fill=\"#00C2FF\"\n                                  d=\"M23.5 17.3l-1.8 1.8c-.3.3-.7.5-1.1.5H10.2c-.5 0-.9-.6-.6-1l1.8-1.8c.3-.3.7-.5 1.1-.5h10.4c.5 0 .9.6.6 1z\"\n                                />\n                              </svg>\n                            } @else if (asset.id === 'usdc') {\n                              <svg\n                                viewBox=\"0 0 32 32\"\n                                class=\"size-8 shrink-0 rounded-full shadow-xs\"\n                                aria-hidden=\"true\"\n                              >\n                                <circle cx=\"16\" cy=\"16\" r=\"16\" fill=\"#2775CA\" />\n                                <path\n                                  fill=\"#ffffff\"\n                                  d=\"M16 6a10 10 0 1010 10A10.01 10.01 0 0016 6zm0 18a8 8 0 118-8 8.01 8.01 0 01-8 8zm1-12h-2v1.1a3.5 3.5 0 00-2 3.1c0 2 1.5 2.7 3 3.1 1.2.3 1.8.6 1.8 1.2s-.6 1.1-1.6 1.1a3.4 3.4 0 01-2.4-.9l-.8 1.4a4.8 4.8 0 003 1.1V20h2v-1.1a3.4 3.4 0 002-3.1c0-2.1-1.6-2.8-3.1-3.2-1.1-.3-1.7-.6-1.7-1.1 0-.5.5-1 1.5-1a3.1 3.1 0 012 .7l.8-1.4a4.5 4.5 0 00-2.5-.9z\"\n                                />\n                              </svg>\n                            } @else {\n                              <svg\n                                viewBox=\"0 0 32 32\"\n                                class=\"size-8 shrink-0 rounded-full shadow-xs\"\n                                aria-hidden=\"true\"\n                              >\n                                <circle cx=\"16\" cy=\"16\" r=\"16\" fill=\"#375BD2\" />\n                                <path\n                                  fill=\"#ffffff\"\n                                  d=\"M16 7l-7.8 4.5v9L16 25l7.8-4.5v-9L16 7zm5.2 12l-5.2 3-5.2-3v-6l5.2-3 5.2 3v6z\"\n                                />\n                              </svg>\n                            }\n                            <div>\n                              <div class=\"text-foreground flex items-center gap-1.5 text-sm font-medium\">\n                                {{ asset.name }}\n                              </div>\n                              <div class=\"text-muted-foreground font-mono text-xs\">{{ asset.symbol }}</div>\n                            </div>\n                          </div>\n                        </td>\n\n                        <!-- Current Price & 24h Change -->\n                        <td ui-table-cell class=\"py-3.5 text-right\">\n                          <div class=\"text-foreground text-sm font-medium tabular-nums\">{{ asset.price }}</div>\n                          <div [class]=\"trendClass(asset)\">\n                            @if (asset.isPositive) {\n                              <lucide-icon [img]=\"TrendingUp\" class=\"size-3\" />\n                            } @else {\n                              <lucide-icon [img]=\"TrendingDown\" class=\"size-3\" />\n                            }\n                            {{ asset.change24h }}\n                          </div>\n                        </td>\n\n                        <!-- Holdings Amount & Fiat Value -->\n                        <td ui-table-cell class=\"py-3.5 text-right\">\n                          <div class=\"text-foreground text-sm font-medium tabular-nums\">{{ asset.balance }}</div>\n                          <div class=\"text-muted-foreground text-xs tabular-nums\">{{ asset.fiatValue }}</div>\n                        </td>\n\n                        <!-- Portfolio Share -->\n                        <td ui-table-cell class=\"hidden py-3.5 text-right sm:table-cell\">\n                          <span ui-badge variant=\"outline\" class=\"border-border/80 font-mono text-xs tabular-nums\">\n                            {{ asset.allocation }}\n                          </span>\n                        </td>\n\n                        <!-- Actions -->\n                        <td ui-table-cell class=\"py-3.5 pr-6 text-right\">\n                          <div class=\"flex items-center justify-end gap-1.5\">\n                            <button\n                              ui-button\n                              variant=\"outline\"\n                              size=\"sm\"\n                              class=\"h-7 px-2.5 text-xs shadow-xs\"\n                              (click)=\"selectTradePair(asset.symbol)\"\n                            >\n                              Trade\n                            </button>\n                            <button\n                              ui-button\n                              variant=\"ghost\"\n                              size=\"sm\"\n                              class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                            >\n                              Transfer\n                            </button>\n                          </div>\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right Column: Quick Swap Widget & Security Info (4 cols) -->\n        <div class=\"space-y-6 lg:col-span-4\">\n          <!-- Quick Swap Card -->\n          <div ui-card class=\"border-border shadow-xs\">\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex items-center justify-between\">\n                <h3 ui-card-title class=\"text-foreground flex items-center gap-1.5 text-base font-semibold\">\n                  <lucide-icon [img]=\"RefreshCw\" class=\"text-primary size-4\" />\n                  Quick Swap\n                </h3>\n                <!-- Slippage Settings -->\n                <div class=\"flex items-center gap-1\">\n                  @for (opt of slippageOptions; track opt) {\n                    <button type=\"button\" [class]=\"slippageClass(opt)\" (click)=\"slippage.set(opt)\">{{ opt }}%</button>\n                  }\n                </div>\n              </div>\n              <p ui-card-description class=\"text-muted-foreground text-xs\">\n                Swap instant liquidity across decentralized pools.\n              </p>\n            </div>\n\n            <div ui-card-content class=\"space-y-3\">\n              <!-- From Token Box -->\n              <div class=\"bg-muted/40 border-border/80 space-y-2 rounded-lg border p-3\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <label for=\"swap-pay-input\" class=\"font-medium\">You Pay</label>\n                  <div class=\"flex items-center gap-1.5\">\n                    <span class=\"tabular-nums\">Balance: {{ fromAsset().balance }}</span>\n                    <button\n                      type=\"button\"\n                      class=\"text-primary focus-visible:ring-ring min-h-6 rounded text-xs font-semibold uppercase hover:underline focus-visible:ring-1 focus-visible:outline-none\"\n                      (click)=\"setMaxPay()\"\n                    >\n                      MAX\n                    </button>\n                  </div>\n                </div>\n\n                <div class=\"flex items-center justify-between gap-3\">\n                  <ui-input\n                    id=\"swap-pay-input\"\n                    [value]=\"payAmount()\"\n                    (valueChange)=\"payAmount.set($event)\"\n                    type=\"number\"\n                    step=\"any\"\n                    min=\"0\"\n                    class=\"h-8 border-none px-0 text-lg font-semibold tabular-nums shadow-none focus-within:ring-0\"\n                    placeholder=\"0.0\"\n                  />\n\n                  <!-- From Token Selector Pill -->\n                  <div\n                    class=\"bg-background border-border flex shrink-0 items-center gap-1.5 rounded-full border px-2.5 py-1 shadow-xs select-none\"\n                  >\n                    <span\n                      class=\"size-2 shrink-0 rounded-full\"\n                      [style.backgroundColor]=\"fromAsset().color\"\n                      aria-hidden=\"true\"\n                    ></span>\n                    <span class=\"text-foreground text-xs font-semibold\">{{ fromAsset().symbol }}</span>\n                  </div>\n                </div>\n\n                <div class=\"text-muted-foreground text-xs tabular-nums\">≈ {{ fiatPayFormatted() }}</div>\n              </div>\n\n              <!-- Invert Flip Button -->\n              <div class=\"relative z-10 -my-1 flex justify-center\">\n                <button\n                  ui-button\n                  variant=\"outline\"\n                  size=\"icon-sm\"\n                  class=\"border-border bg-background hover:bg-muted text-muted-foreground hover:text-foreground size-8 rounded-full shadow-xs transition-[color,background-color,border-color,box-shadow,opacity,transform,scale,translate,rotate] active:scale-95\"\n                  aria-label=\"Flip swap token pair\"\n                  (click)=\"flipTokens()\"\n                >\n                  <lucide-icon [img]=\"ArrowDownUp\" class=\"size-4\" />\n                </button>\n              </div>\n\n              <!-- To Token Box -->\n              <div class=\"bg-muted/40 border-border/80 space-y-2 rounded-lg border p-3\">\n                <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                  <span class=\"font-medium\">You Receive</span>\n                  <span class=\"tabular-nums\">Balance: {{ toAsset().balance }}</span>\n                </div>\n\n                <div class=\"flex items-center justify-between gap-3\">\n                  <div class=\"text-foreground flex h-8 items-center text-lg font-semibold tabular-nums\">\n                    {{ calculatedReceive() }}\n                  </div>\n\n                  <!-- To Token Selector Pill -->\n                  <div\n                    class=\"bg-background border-border flex shrink-0 items-center gap-1.5 rounded-full border px-2.5 py-1 shadow-xs select-none\"\n                  >\n                    <span\n                      class=\"size-2 shrink-0 rounded-full\"\n                      [style.backgroundColor]=\"toAsset().color\"\n                      aria-hidden=\"true\"\n                    ></span>\n                    <span class=\"text-foreground text-xs font-semibold\">{{ toAsset().symbol }}</span>\n                  </div>\n                </div>\n\n                <div class=\"text-muted-foreground text-xs tabular-nums\">≈ {{ fiatReceiveFormatted() }}</div>\n              </div>\n\n              <!-- Trade Details Summary -->\n              <div\n                class=\"border-border/60 bg-muted/20 text-muted-foreground space-y-1.5 rounded-md border p-2.5 text-xs\"\n              >\n                <div class=\"flex items-center justify-between\">\n                  <span>Exchange Rate</span>\n                  <span class=\"text-foreground font-medium tabular-nums\">{{ exchangeRateFormatted() }}</span>\n                </div>\n                <div class=\"flex items-center justify-between\">\n                  <span class=\"flex items-center gap-1\">\n                    <lucide-icon [img]=\"Fuel\" class=\"text-muted-foreground size-3\" />\n                    Est. Network Gas\n                  </span>\n                  <span class=\"text-foreground font-medium tabular-nums\">~$3.40 (Fast)</span>\n                </div>\n                <div class=\"flex items-center justify-between\">\n                  <span>Slippage Tolerance</span>\n                  <span class=\"text-foreground font-medium tabular-nums\">{{ slippage() }}%</span>\n                </div>\n                <div class=\"flex items-center justify-between\">\n                  <span>Price Impact</span>\n                  <span class=\"text-success text-success font-medium tabular-nums\">&lt; 0.01%</span>\n                </div>\n              </div>\n\n              <!-- Execute Swap Button -->\n              <button\n                ui-button\n                class=\"w-full font-semibold shadow-xs\"\n                size=\"lg\"\n                [disabled]=\"swapDisabled\"\n                (click)=\"handleExecuteSwap()\"\n              >\n                @if (isSwapping()) {\n                  <lucide-icon [img]=\"RefreshCw\" class=\"size-4 animate-spin\" />\n                } @else if (swapSuccess()) {\n                  <lucide-icon [img]=\"Check\" class=\"text-success size-4\" />\n                }\n                @if (isSwapping()) {\n                  <span>Routing Transaction...</span>\n                } @else if (swapSuccess()) {\n                  <span>Swap Confirmed!</span>\n                } @else {\n                  <span>Swap {{ fromAsset().symbol }} for {{ toAsset().symbol }}</span>\n                }\n              </button>\n\n              <p class=\"text-muted-foreground text-center text-xs\">\n                Direct routing via Uniswap v3 & Curve liquidity pools.\n              </p>\n            </div>\n          </div>\n\n          <!-- Security & Vault Status Summary -->\n          <div ui-card class=\"border-border shadow-xs\">\n            <div ui-card-header class=\"pb-2\">\n              <h3 ui-card-title class=\"text-foreground flex items-center gap-1.5 text-sm font-semibold\">\n                <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-4\" />\n                Vault Security & Policies\n              </h3>\n            </div>\n            <div ui-card-content class=\"text-muted-foreground space-y-3 text-xs\">\n              <div class=\"flex items-center justify-between\">\n                <span>Threshold Policy</span>\n                <span class=\"text-foreground font-mono font-medium\">3 / 5 Approvals</span>\n              </div>\n              <div ui-separator class=\"my-1\"></div>\n              <div class=\"flex items-center justify-between\">\n                <span>Daily Spend Limit</span>\n                <span class=\"text-foreground font-medium tabular-nums\">$500,000.00</span>\n              </div>\n              <div ui-separator class=\"my-1\"></div>\n              <div class=\"flex items-center justify-between\">\n                <span>Hardware Key Modules</span>\n                <span ui-badge variant=\"outline\" class=\"border-success/30 text-success text-xs font-normal\">\n                  5 Ledger HSMs Active\n                </span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiCryptoWalletPortfolioComponent {\n  protected readonly ArrowDownLeft = ArrowDownLeft\n  protected readonly ArrowDownUp = ArrowDownUp\n  protected readonly ArrowLeftRight = ArrowLeftRight\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly Check = Check\n  protected readonly Copy = Copy\n  protected readonly Fuel = Fuel\n  protected readonly RefreshCw = RefreshCw\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly TrendingDown = TrendingDown\n  protected readonly TrendingUp = TrendingUp\n  protected readonly Wallet = Wallet\n\n  protected readonly assets = cryptoAssets\n  protected readonly shortAddress = walletShortAddress\n  protected readonly slippageOptions = slippageOptions\n\n  @Input('class') className?: string\n\n  readonly copied = signal(false)\n  readonly fromTokenSymbol = signal('ETH')\n  readonly toTokenSymbol = signal('USDC')\n  readonly payAmount = signal('1.5')\n  readonly slippage = signal('0.5')\n  readonly isSwapping = signal(false)\n  readonly swapSuccess = signal(false)\n\n  private copyTimer: ReturnType<typeof setTimeout> | undefined\n  private swapTimers: ReturnType<typeof setTimeout>[] = []\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => {\n      clearTimeout(this.copyTimer)\n      for (const t of this.swapTimers) clearTimeout(t)\n    })\n  }\n\n  // Quick Swap State\n  readonly tokenMap = computed(() => {\n    const map: Record<string, CryptoAsset> = {}\n    for (const asset of cryptoAssets) map[asset.symbol] = asset\n    return map\n  })\n\n  readonly fromAsset = computed(() => this.tokenMap()[this.fromTokenSymbol()] ?? cryptoAssets[0]!)\n  readonly toAsset = computed(() => this.tokenMap()[this.toTokenSymbol()] ?? cryptoAssets[3]!)\n\n  readonly calculatedReceive = computed(() => {\n    const amount = parseFloat(this.payAmount()) || 0\n    if (amount <= 0) return '0.00'\n    const fromFiat = amount * this.fromAsset().rawPrice\n    const receiveUnits = fromFiat / this.toAsset().rawPrice\n    if (this.toAsset().rawPrice >= 100) return receiveUnits.toFixed(4)\n    return receiveUnits.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })\n  })\n\n  readonly fiatPayFormatted = computed(() =>\n    ((parseFloat(this.payAmount()) || 0) * this.fromAsset().rawPrice).toLocaleString('en-US', {\n      style: 'currency',\n      currency: 'USD',\n    }),\n  )\n\n  readonly fiatReceiveFormatted = computed(() =>\n    ((parseFloat(this.payAmount()) || 0) * this.fromAsset().rawPrice).toLocaleString('en-US', {\n      style: 'currency',\n      currency: 'USD',\n    }),\n  )\n\n  readonly exchangeRateFormatted = computed(() => {\n    const rate = this.fromAsset().rawPrice / this.toAsset().rawPrice\n    const formattedRate =\n      rate > 100\n        ? rate.toLocaleString('en-US', { maximumFractionDigits: 2 })\n        : rate.toLocaleString('en-US', { maximumFractionDigits: 6 })\n    return `1 ${this.fromAsset().symbol} ≈ ${formattedRate} ${this.toAsset().symbol}`\n  })\n\n  get rootClass(): string {\n    return cn('mx-auto w-full max-w-6xl space-y-6', this.className)\n  }\n\n  get swapDisabled(): boolean {\n    return this.isSwapping() || (parseFloat(this.payAmount()) || 0) <= 0\n  }\n\n  trendClass(asset: CryptoAsset): string {\n    return cn(\n      'flex items-center justify-end gap-0.5 text-xs font-medium tabular-nums',\n      asset.isPositive ? 'text-success' : 'text-destructive',\n    )\n  }\n\n  slippageClass(opt: string): string {\n    return cn(\n      'focus-visible:ring-ring min-h-6 rounded px-1.5 py-0.5 font-mono text-xs transition-colors focus-visible:ring-1 focus-visible:outline-none',\n      this.slippage() === opt\n        ? 'bg-primary text-primary-foreground font-semibold'\n        : 'text-muted-foreground hover:text-foreground bg-muted/60',\n    )\n  }\n\n  async copyAddress(): Promise<void> {\n    try {\n      await navigator.clipboard.writeText(walletFullAddress)\n      this.copied.set(true)\n      clearTimeout(this.copyTimer)\n      this.copyTimer = setTimeout(() => this.copied.set(false), 2000)\n    } catch {\n      // Clipboard fallback\n    }\n  }\n\n  selectTradePair(symbol: string): void {\n    this.fromTokenSymbol.set(symbol)\n    this.toTokenSymbol.set(symbol === 'USDC' ? 'ETH' : 'USDC')\n  }\n\n  flipTokens(): void {\n    const from = this.fromTokenSymbol()\n    this.fromTokenSymbol.set(this.toTokenSymbol())\n    this.toTokenSymbol.set(from)\n  }\n\n  setMaxPay(): void {\n    this.payAmount.set(String(this.fromAsset().rawBalance))\n  }\n\n  handleExecuteSwap(): void {\n    this.isSwapping.set(true)\n    this.swapTimers.push(\n      setTimeout(() => {\n        this.isSwapping.set(false)\n        this.swapSuccess.set(true)\n        this.swapTimers.push(setTimeout(() => this.swapSuccess.set(false), 3000))\n      }, 1200),\n    )\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/crypto-wallet-portfolio/crypto-wallet-portfolio.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/crypto-wallet-portfolio/index.ts",
      "content": "export {\n  UiCryptoWalletPortfolioComponent,\n  cryptoAssets,\n  walletFullAddress,\n  walletShortAddress,\n  type CryptoAsset,\n} from './crypto-wallet-portfolio.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/crypto-wallet-portfolio/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "Coinbase and Phantom-style multi-asset crypto holdings dashboard: treasury header with address copy and network badge, portfolio balance hero with 24h PnL and multi-asset allocation bar, asset holdings table with real-time token metrics, and an interactive quick swap calculator.",
  "categories": [
    "finance",
    "app",
    "dashboard"
  ]
}