{
  "name": "market-components-markettable",
  "type": "registry:component",
  "dependencies": [
    "@radix-ui/react-icons"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/market/components/MarketTable.tsx",
      "type": "registry:component",
      "content": "import { ExternalLinkIcon, MagnifyingGlassIcon } from \"@radix-ui/react-icons\";\n// MarketTable Component - Display marketplace listings in a table\nimport { useState } from \"react\";\nimport { responsive } from \"../../../lib/layout-constants.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { Avatar, AvatarFallback } from \"../../ui/avatar.js\";\nimport { Badge } from \"../../ui/badge.js\";\nimport { Button } from \"../../ui/button.js\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"../../ui/select.js\";\nimport { Skeleton } from \"../../ui/skeleton.js\";\nimport {\n\tTable,\n\tTableBody,\n\tTableCell,\n\tTableHead,\n\tTableHeader,\n\tTableRow,\n} from \"../../ui/table.js\";\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from \"../../ui/tooltip.js\";\nimport {\n\tabbreviateNumber,\n\tformatBSV,\n\tformatTokenAmount,\n} from \"../../wallet/utils/currency.js\";\nimport type { MarketListing } from \"../types/listings.js\";\nimport { AssetType } from \"../types/market.js\";\nimport { BuyListingButton } from \"./BuyListingButton.js\";\n\nexport interface MarketTableProps {\n\tlistings: MarketListing[];\n\tloading?: boolean;\n\terror?: string;\n\tonListingClick?: (listing: MarketListing) => void;\n\tonBuySuccess?: (txid: string, listing: MarketListing) => void;\n\tonBuyError?: (error: Error, listing: MarketListing) => void;\n\tshowAssetType?: boolean;\n\tshowSeller?: boolean;\n\tmaxItems?: number;\n\tclassName?: string;\n}\n\nexport function MarketTable({\n\tlistings,\n\tloading = false,\n\terror,\n\tonListingClick,\n\tonBuySuccess,\n\tonBuyError,\n\tshowAssetType = true,\n\tshowSeller = true,\n\tmaxItems = 50,\n\tclassName,\n}: MarketTableProps) {\n\tconst [sortBy, setSortBy] = useState<\"price\" | \"date\" | \"name\">(\"price\");\n\tconst [sortDirection, setSortDirection] = useState<\"asc\" | \"desc\">(\"asc\");\n\n\tif (loading) {\n\t\treturn (\n\t\t\t<div className={className}>\n\t\t\t\t<Table>\n\t\t\t\t\t<TableHeader>\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableHead>Item</TableHead>\n\t\t\t\t\t\t\t{showAssetType && <TableHead>Type</TableHead>}\n\t\t\t\t\t\t\t<TableHead>Amount</TableHead>\n\t\t\t\t\t\t\t<TableHead>Price</TableHead>\n\t\t\t\t\t\t\t{showSeller && <TableHead>Seller</TableHead>}\n\t\t\t\t\t\t\t<TableHead>Action</TableHead>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t</TableHeader>\n\t\t\t\t\t<TableBody>\n\t\t\t\t\t\t{Array.from(\n\t\t\t\t\t\t\t{ length: 5 },\n\t\t\t\t\t\t\t(_, i) => `loading-row-${Date.now()}-${i}`,\n\t\t\t\t\t\t).map((key) => (\n\t\t\t\t\t\t\t<TableRow key={key}>\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-6 h-6 rounded\" />\n\t\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-20 h-4\" />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t{showAssetType && (\n\t\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-12 h-5\" />\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-16 h-4\" />\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-20 h-4\" />\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t{showSeller && (\n\t\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-24 h-4\" />\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<Skeleton className=\"w-16 h-8\" />\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</TableBody>\n\t\t\t\t</Table>\n\t\t\t</div>\n\t\t);\n\t}\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div className={className}>\n\t\t\t\t<div className=\"flex flex-col gap-3 items-center py-6\">\n\t\t\t\t\t<p className=\"text-sm text-destructive\">Failed to load listings</p>\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">{error}</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\tif (listings.length === 0) {\n\t\treturn (\n\t\t\t<div className={className}>\n\t\t\t\t<div className=\"flex flex-col gap-3 items-center py-6\">\n\t\t\t\t\t<MagnifyingGlassIcon className=\"w-6 h-6 text-muted-foreground\" />\n\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">No listings found</p>\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\tTry adjusting your search filters\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// Sort listings\n\tconst sortedListings = [...listings].slice(0, maxItems).sort((a, b) => {\n\t\tlet comparison = 0;\n\n\t\tswitch (sortBy) {\n\t\t\tcase \"price\":\n\t\t\t\tcomparison = a.priceSats - b.priceSats;\n\t\t\t\tbreak;\n\t\t\tcase \"date\":\n\t\t\t\tcomparison = (a.createdAt || 0) - (b.createdAt || 0);\n\t\t\t\tbreak;\n\t\t\tcase \"name\":\n\t\t\t\tcomparison = (a.symbol || \"\").localeCompare(b.symbol || \"\");\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn sortDirection === \"desc\" ? -comparison : comparison;\n\t});\n\n\tconst getAssetTypeColor = (assetType: AssetType) => {\n\t\tswitch (assetType) {\n\t\t\tcase AssetType.Ordinals:\n\t\t\t\treturn \"orange\";\n\t\t\tcase AssetType.BSV20:\n\t\t\t\treturn \"blue\";\n\t\t\tcase AssetType.BSV21:\n\t\t\t\treturn \"green\";\n\t\t\tdefault:\n\t\t\t\treturn \"gray\";\n\t\t}\n\t};\n\n\treturn (\n\t\t<div className={className}>\n\t\t\t{/* Sort Controls */}\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex justify-between mb-4\",\n\t\t\t\t\t\"flex-col sm:flex-row\",\n\t\t\t\t\t\"items-start sm:items-center\",\n\t\t\t\t\t\"gap-2 sm:gap-3\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t{listings.length} listing{listings.length === 1 ? \"\" : \"s\"}\n\t\t\t\t</p>\n\n\t\t\t\t<div className=\"flex gap-2 items-center flex-wrap\">\n\t\t\t\t\t<span className=\"hidden sm:block text-sm text-muted-foreground\">\n\t\t\t\t\t\tSort by:\n\t\t\t\t\t</span>\n\t\t\t\t\t<Select\n\t\t\t\t\t\tvalue={sortBy}\n\t\t\t\t\t\tonValueChange={(value: \"price\" | \"date\" | \"name\") =>\n\t\t\t\t\t\t\tsetSortBy(value)\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t\t\t<SelectTrigger className=\"w-32\">\n\t\t\t\t\t\t\t<SelectValue />\n\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t<SelectItem value=\"price\">Price</SelectItem>\n\t\t\t\t\t\t\t<SelectItem value=\"date\">Date</SelectItem>\n\t\t\t\t\t\t\t<SelectItem value=\"name\">Name</SelectItem>\n\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t</Select>\n\n\t\t\t\t\t<Select\n\t\t\t\t\t\tvalue={sortDirection}\n\t\t\t\t\t\tonValueChange={(value: \"asc\" | \"desc\") => setSortDirection(value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<SelectTrigger className=\"w-32\">\n\t\t\t\t\t\t\t<SelectValue />\n\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t<SelectItem value=\"asc\">Low to High</SelectItem>\n\t\t\t\t\t\t\t<SelectItem value=\"desc\">High to Low</SelectItem>\n\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t</Select>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{/* Table */}\n\t\t\t<div className=\"overflow-x-auto md:overflow-x-visible\">\n\t\t\t\t<Table>\n\t\t\t\t\t<TableHeader>\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableHead>Item</TableHead>\n\t\t\t\t\t\t\t{showAssetType && <TableHead>Type</TableHead>}\n\t\t\t\t\t\t\t<TableHead>Amount</TableHead>\n\t\t\t\t\t\t\t<TableHead>Price</TableHead>\n\t\t\t\t\t\t\t{showSeller && <TableHead>Seller</TableHead>}\n\t\t\t\t\t\t\t<TableHead>Action</TableHead>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t</TableHeader>\n\t\t\t\t\t<TableBody>\n\t\t\t\t\t\t{sortedListings.map((listing) => (\n\t\t\t\t\t\t\t<TableRow\n\t\t\t\t\t\t\t\tkey={`${listing.txid}-${listing.vout}`}\n\t\t\t\t\t\t\t\tclassName={onListingClick ? \"cursor-pointer\" : \"\"}\n\t\t\t\t\t\t\t\tonClick={() => onListingClick?.(listing)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{/* Item */}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t\t<Avatar className=\"h-6 w-6\">\n\t\t\t\t\t\t\t\t\t\t\t<AvatarFallback>\n\t\t\t\t\t\t\t\t\t\t\t\t{listing.symbol?.slice(0, 2).toUpperCase() || \"??\"}\n\t\t\t\t\t\t\t\t\t\t\t</AvatarFallback>\n\t\t\t\t\t\t\t\t\t\t</Avatar>\n\t\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t\t{listing.symbol || \"Unknown\"}\n\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t{listing.tokenId && (\n\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-xs text-muted-foreground font-mono\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{listing.tokenId.slice(0, 8)}...\n\t\t\t\t\t\t\t\t\t\t\t\t\t{listing.tokenId.slice(-8)}\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TableCell>\n\n\t\t\t\t\t\t\t\t{/* Type */}\n\t\t\t\t\t\t\t\t{showAssetType && (\n\t\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\tlisting.assetType === AssetType.Ordinals\n\t\t\t\t\t\t\t\t\t\t\t\t\t? \"bg-orange-100 text-orange-700\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t: listing.assetType === AssetType.BSV20\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? \"bg-blue-100 text-blue-700\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: \"bg-green-100 text-green-700\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{listing.assetType.toUpperCase()}\n\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Amount */}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t{listing.tokenAmount ? (\n\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm\">\n\t\t\t\t\t\t\t\t\t\t\t{formatTokenAmount(\n\t\t\t\t\t\t\t\t\t\t\t\tlisting.tokenAmount,\n\t\t\t\t\t\t\t\t\t\t\t\tlisting.decimals || 0,\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">1 NFT</p>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</TableCell>\n\n\t\t\t\t\t\t\t\t{/* Price */}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t{formatBSV(listing.priceSats)} BSV\n\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t~{abbreviateNumber(listing.priceSats)} sats\n\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TableCell>\n\n\t\t\t\t\t\t\t\t{/* Seller */}\n\t\t\t\t\t\t\t\t{showSeller && (\n\t\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t\t<TooltipProvider>\n\t\t\t\t\t\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground font-mono\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{listing.payAddress?.slice(0, 8) || \"Unknown\"}...\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{listing.payAddress?.slice(-6) || \"\"}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{listing.payAddress || \"Unknown address\"}\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t</TooltipProvider>\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{/* Action */}\n\t\t\t\t\t\t\t\t<TableCell>\n\t\t\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t\t\t<BuyListingButton\n\t\t\t\t\t\t\t\t\t\t\tlisting={listing}\n\t\t\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t\t\t\tbuttonText=\"Buy\"\n\t\t\t\t\t\t\t\t\t\t\tonSuccess={(txid) => onBuySuccess?.(txid, listing)}\n\t\t\t\t\t\t\t\t\t\t\tonError={(error) => onBuyError?.(error, listing)}\n\t\t\t\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t\t\t\t<TooltipProvider>\n\t\t\t\t\t\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={(e) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Could open external explorer or detailed view\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ExternalLinkIcon className=\"w-3 h-3\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t\t\t\t\t<TooltipContent>View details</TooltipContent>\n\t\t\t\t\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t\t\t\t\t</TooltipProvider>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</TableBody>\n\t\t\t\t</Table>\n\t\t\t</div>\n\n\t\t\t{/* Show truncation notice */}\n\t\t\t{listings.length > maxItems && (\n\t\t\t\t<div className=\"flex justify-center mt-3\">\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\tShowing {maxItems} of {listings.length} listings\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// Simplified version for compact display\nexport function CompactMarketTable({\n\tlistings,\n\tmaxItems = 10,\n\tclassName,\n}: Pick<MarketTableProps, \"listings\" | \"maxItems\" | \"className\">) {\n\treturn (\n\t\t<MarketTable\n\t\t\tlistings={listings}\n\t\t\tmaxItems={maxItems}\n\t\t\tshowAssetType={false}\n\t\t\tshowSeller={false}\n\t\t\tclassName={className}\n\t\t/>\n\t);\n}\n",
      "target": "<%- config.aliases.components %>/markettable.tsx"
    }
  ]
}