Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>Wallet Balance – Demo UI</title> | |
| <style> | |
| :root{ | |
| --bg:#0f1220;--card:#171a2b;--text:#e7e9f3;--muted:#a7adc2;--accent:#6d8dff;--accent-2:#9b6dff;--danger:#ff6d6d;--ok:#60d394; | |
| --border:rgba(255,255,255,.08);--shadow:0 10px 30px rgba(0,0,0,.35); | |
| } | |
| *{box-sizing:border-box} body{margin:0;background:radial-gradient(1200px 600px at 10% -10%, #1e2240 0%, #0f1220 60%), #0f1220;color:var(--text);font:16px/1.4 system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif} | |
| .container{max-width:900px;margin:40px auto;padding:16px} | |
| .banner{background:linear-gradient(90deg,rgba(255,255,255,.06),rgba(255,255,255,.02));border:1px solid var(--border);padding:12px 14px;border-radius:14px;margin-bottom:16px} | |
| .banner strong{color:var(--ok)} | |
| .row{display:grid;grid-template-columns:1.2fr .8fr auto;gap:10px} | |
| .card{background:linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.02));border:1px solid var(--border);border-radius:20px;box-shadow:var(--shadow);padding:18px} | |
| .title{font-size:24px;font-weight:700;margin:2px 0 14px} | |
| label{display:block;font-size:12px;color:var(--muted);margin-bottom:6px} | |
| input,select,button{width:100%;border-radius:14px;border:1px solid var(--border);padding:12px 14px;background:#0f1220;color:var(--text)} | |
| input:focus,select:focus,button:focus{outline:2px solid color-mix(in oklab, var(--accent) 60%, white)} | |
| button{cursor:pointer;background:linear-gradient(135deg, var(--accent), var(--accent-2));border:none;font-weight:700} | |
| button[disabled]{opacity:.6;cursor:not-allowed} | |
| .muted{color:var(--muted)} | |
| .result{display:none;margin-top:14px;border-top:1px dashed var(--border);padding-top:14px} | |
| .result.visible{display:block} | |
| .pill{display:inline-flex;gap:8px;align-items:center;border:1px solid var(--border);padding:6px 10px;border-radius:999px;background:rgba(255,255,255,.04);font-size:12px} | |
| .grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px} | |
| .footer{margin-top:30px;color:var(--muted);font-size:12px;text-align:center} | |
| .error{color:var(--danger);font-size:13px;margin-top:8px} | |
| .copy{background:transparent;border:1px dashed var(--border);padding:8px 12px} | |
| @media (max-width:800px){.row{grid-template-columns:1fr}} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="banner"> | |
| <strong>Demo only:</strong> This page is a front‑end example. It does <em>not</em> query a real blockchain or wallet provider. Replace the mock code with your own API calls if you are building a legitimate balance checker. | |
| </div> | |
| <div class="card"> | |
| <div class="title">Wallet Balance</div> | |
| <div class="row"> | |
| <div> | |
| <label for="address">Wallet Address</label> | |
| <input id="address" placeholder="0x… or other format" autocomplete="off" /> | |
| </div> | |
| <div> | |
| <label for="network">Network</label> | |
| <select id="network"> | |
| <option value="ethereum" selected>Ethereum</option> | |
| <option value="bsc">BNB Smart Chain</option> | |
| <option value="solana">Solana</option> | |
| <option value="polygon">Polygon</option> | |
| <option value="tron">TRON</option> | |
| </select> | |
| </div> | |
| <div style="align-self:end"> | |
| <button id="checkBtn">Check Balance</button> | |
| </div> | |
| </div> | |
| <div class="error" id="error"></div> | |
| <div class="result" id="result"> | |
| <div class="grid"> | |
| <div> | |
| <div class="muted">Normalized Balance</div> | |
| <div id="balance" style="font-size:28px;font-weight:800;">—</div> | |
| </div> | |
| <div> | |
| <div class="muted">Address</div> | |
| <div style="display:flex;gap:8px;align-items:center"> | |
| <code id="addrOut" style="font-size:12px;opacity:.9"></code> | |
| <button class="pill copy" id="copyBtn" title="Copy address">Copy</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div style="margin-top:10px" class="muted" id="note"></div> | |
| </div> | |
| </div> | |
| <div class="footer"> | |
| <p>For production, use official SDKs/APIs (e.g., Alchemy, Infura, QuickNode, Solana RPC), validate inputs, and never misrepresent balances or brands.</p> | |
| </div> | |
| </div> | |
| <script> | |
| // --- Simple deterministic mock so results are stable for the same input --- | |
| function hashToNumber(str){ | |
| let h1 = 0xdeadbeef ^ str.length, h2 = 0x41c6ce57 ^ str.length; | |
| for (let i=0; i<str.length; i++){ | |
| const ch = str.charCodeAt(i); | |
| h1 = Math.imul(h1 ^ ch, 2654435761); | |
| h2 = Math.imul(h2 ^ ch, 1597334677); | |
| } | |
| h1 = (h1 ^ (h1>>>16)) >>> 0; h2 = (h2 ^ (h2>>>13)) >>> 0; | |
| return (h1 + h2) >>> 0; // 0..2^32-1 | |
| } | |
| function format(num){ | |
| return new Intl.NumberFormat(undefined, {maximumFractionDigits:6}).format(num); | |
| } | |
| const address = document.getElementById('address'); | |
| const network = document.getElementById('network'); | |
| const btn = document.getElementById('checkBtn'); | |
| const error = document.getElementById('error'); | |
| const result = document.getElementById('result'); | |
| const balanceEl = document.getElementById('balance'); | |
| const addrOut = document.getElementById('addrOut'); | |
| const note = document.getElementById('note'); | |
| const copyBtn = document.getElementById('copyBtn'); | |
| function validate(addr){ | |
| if (!addr || addr.trim().length < 6) return 'Enter a valid address.'; | |
| // Very light checks – expand per network as needed | |
| if (network.value === 'ethereum' || network.value === 'bsc' || network.value === 'polygon'){ | |
| if (!/^0x[0-9a-fA-F]{6,}$/.test(addr)) return 'Expected an 0x… style address for this network.'; | |
| } | |
| return ''; | |
| } | |
| btn.addEventListener('click', () => { | |
| error.textContent = ''; | |
| result.classList.remove('visible'); | |
| const addr = address.value.trim(); | |
| const v = validate(addr); | |
| if (v){ error.textContent = v; return; } | |
| btn.disabled = true; btn.textContent = 'Checking…'; | |
| // Simulate delay | |
| setTimeout(() => { | |
| const seed = hashToNumber(addr + '|' + network.value); | |
| const base = (seed % 10_000_000) / 100_000; // up to 100 | |
| const decimals = network.value === 'solana' || network.value === 'tron' ? 2 : 4; | |
| const displayed = Number(base.toFixed(decimals)); | |
| balanceEl.textContent = format(displayed); | |
| addrOut.textContent = addr; | |
| note.textContent = `Mock value based on input • Network: ${network.options[network.selectedIndex].text}`; | |
| result.classList.add('visible'); | |
| btn.disabled = false; btn.textContent = 'Check Balance'; | |
| }, 500); | |
| }); | |
| copyBtn.addEventListener('click', async () => { | |
| const text = addrOut.textContent || ''; | |
| if (!text) return; | |
| try { await navigator.clipboard.writeText(text); copyBtn.textContent = 'Copied'; setTimeout(()=>copyBtn.textContent='Copy', 1200);} catch(e){ console.warn(e); } | |
| }); | |
| </script> | |
| </body> | |
| </html> |