From ba2002574cea899357deaa40f77cec4095f15cdb Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Thu, 20 Nov 2025 17:14:01 +1100 Subject: [PATCH] feat: Add coin rendering --- server.py | 6 ++ templates/index.html | 152 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index a8a4b17..241e02c 100644 --- a/server.py +++ b/server.py @@ -103,6 +103,12 @@ def name_route(name): return render_template("index.html", datetime=current_datetime) +@app.route("/coin//") +def coin_route(coin_hash, index): + current_datetime = datetime.now().strftime("%d %b %Y %I:%M %p") + return render_template("index.html", datetime=current_datetime) + + @app.route("/") def catch_all(path: str): if os.path.isfile("templates/" + path): diff --git a/templates/index.html b/templates/index.html index b42a77e..59e7afd 100644 --- a/templates/index.html +++ b/templates/index.html @@ -169,6 +169,11 @@ searchName(); break; } + } else if (parts.length === 3 && parts[0] === 'coin') { + // Handle coin URLs: /coin/hash/index + document.getElementById('coin-hash').value = parts[1]; + document.getElementById('coin-index').value = parts[2]; + searchCoin(); } } @@ -390,6 +395,133 @@ return html; } + // Format address coins nicely + function formatAddressCoins(coins) { + if (!coins || coins.error) { + return `
Error: ${coins.error || 'Invalid coin data'}
`; + } + + if (!Array.isArray(coins) || coins.length === 0) { + return `
No coins found for this address
`; + } + + const formatValue = (value) => (value / 1e6).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' HNS'; + + const totalValue = coins.reduce((sum, coin) => sum + coin.value, 0); + + let html = ` +
+
+

Coins (${coins.length}) - Total: ${formatValue(totalValue)}

+
+ ${coins.map((coin, i) => ` +
+
+ Output #${coin.index} + ${formatValue(coin.value)} +
+
${coin.address}
+
+
${coin.hash}
+
+
+ Height: ${coin.height.toLocaleString()} + Coinbase: ${coin.coinbase ? 'Yes' : 'No'} + Covenant: ${coin.covenant.action} +
+
+ `).join('')} +
+
+ +
+ +
${JSON.stringify(coins, null, 2)}
+
+
+ `; + + return html; + } + + // Format individual coin nicely + function formatCoin(coin) { + if (!coin || coin.error) { + return `
Error: ${coin.error || 'Invalid coin data'}
`; + } + + const formatValue = (value) => (value / 1e6).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' HNS'; + + let html = ` +
+
+

Coin Information

+
+
+ + ${formatValue(coin.value)} +
+
+ + ${coin.index} +
+
+ + ${coin.height.toLocaleString()} +
+
+ + ${coin.coinbase ? 'Yes' : 'No'} +
+
+ + ${coin.version} +
+
+ + ${coin.covenant.action} +
+
+
+ +
+

Transaction Hash

+
+
${coin.hash}
+
+
+ +
+

Address

+
+
${coin.address}
+
+
+ + ${coin.covenant.items && coin.covenant.items.length > 0 ? ` +
+

Covenant Items

+
+ ${coin.covenant.items.map((item, i) => ` +
+ Item ${i}: + ${item} +
+ `).join('')} +
+
+ ` : ''} + +
+ +
${JSON.stringify(coin, null, 2)}
+
+
+ `; + + return html; + } + // Format transaction data nicely function formatTransactionData(tx) { if (!tx || tx.error) { @@ -599,8 +731,16 @@ alert('Please enter an address'); return; } + updateURL('address', address); const data = await apiCall(`coin/address/${address}`); - displayResult('address-result', data); + + // Use formatted display instead of raw JSON + const resultElement = document.getElementById('address-result'); + if (data.error) { + resultElement.innerHTML = `
Error: ${data.error}
`; + } else { + resultElement.innerHTML = formatAddressCoins(data); + } } async function searchName() { @@ -651,8 +791,16 @@ alert('Please enter both coin hash and index'); return; } + updateURL('coin', `${coinHash}/${coinIndex}`); const data = await apiCall(`coin/${coinHash}/${coinIndex}`); - displayResult('coin-result', data); + + // Use formatted display instead of raw JSON + const resultElement = document.getElementById('coin-result'); + if (data.error) { + resultElement.innerHTML = `
Error: ${data.error}
`; + } else { + resultElement.innerHTML = formatCoin(data); + } } // Load status when page loads