diff options
| author | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-12 11:58:03 -0300 |
|---|---|---|
| committer | Nsable-sh <nsable-sh@noreply.git.bitflash.network> | 2026-08-12 11:58:03 -0300 |
| commit | b0ed2ce585d2a6fd7c6d8d4db7422734aedccb58 (patch) | |
| tree | 509f8424e4fed7eb00a1fa3294a26da70eb5e7ef /scripts/build-explorer.py | |
| parent | bc3de301d9ed0e5fb5e2034be2e066d77cf23804 (diff) | |
site: document public deployment contract
Diffstat (limited to 'scripts/build-explorer.py')
| -rwxr-xr-x | scripts/build-explorer.py | 128 |
1 files changed, 84 insertions, 44 deletions
diff --git a/scripts/build-explorer.py b/scripts/build-explorer.py index 97a7f4e..dbb8e17 100755 --- a/scripts/build-explorer.py +++ b/scripts/build-explorer.py | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | import argparse | 4 | import argparse |
| 5 | import hashlib | 5 | import hashlib |
| 6 | import json | 6 | import json |
| 7 | import shutil | ||
| 7 | import sys | 8 | import sys |
| 8 | from pathlib import Path | 9 | from pathlib import Path |
| 9 | 10 | ||
| @@ -148,6 +149,11 @@ def build_explorer(raw_blocks, out_dir): | |||
| 148 | encoding="ascii", | 149 | encoding="ascii", |
| 149 | ) | 150 | ) |
| 150 | (out / "index.html").write_text(INDEX_HTML, encoding="utf-8") | 151 | (out / "index.html").write_text(INDEX_HTML, encoding="utf-8") |
| 152 | (out / "style.css").write_text(STYLE_CSS, encoding="utf-8") | ||
| 153 | (out / "explorer.js").write_text(EXPLORER_JS, encoding="utf-8") | ||
| 154 | logo = Path(__file__).resolve().parents[1] / "docs" / "logo.png" | ||
| 155 | if logo.exists(): | ||
| 156 | shutil.copyfile(logo, out / "logo.png") | ||
| 151 | return len(blocks), len(blocks) - 1 | 157 | return len(blocks), len(blocks) - 1 |
| 152 | 158 | ||
| 153 | 159 | ||
| @@ -167,43 +173,26 @@ INDEX_HTML = r"""<!doctype html> | |||
| 167 | <meta charset="utf-8"> | 173 | <meta charset="utf-8"> |
| 168 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 174 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 169 | <title>Bitflash Block Explorer</title> | 175 | <title>Bitflash Block Explorer</title> |
| 170 | <style> | 176 | <meta name="description" content="Read-only Bitflash block explorer generated from local blk*.dat files."> |
| 171 | :root { color-scheme: light dark; --bg:#fff; --fg:#111; --mut:#666; --line:#e2e2e2; --card:#fafafa; --acc:#2b6cb0; } | 177 | <link rel="icon" href="logo.png" type="image/png"> |
| 172 | @media (prefers-color-scheme: dark){ :root{ --bg:#0e0f11; --fg:#e6e6e6; --mut:#9aa0a6; --line:#26282c; --card:#16181b; --acc:#63b3ed; } } | 178 | <link rel="stylesheet" href="style.css"> |
| 173 | * { box-sizing: border-box; } | 179 | <script src="explorer.js" defer></script> |
| 174 | body { font: 15px/1.5 system-ui, sans-serif; margin:0; background:var(--bg); color:var(--fg); } | ||
| 175 | header { padding:20px 24px; border-bottom:1px solid var(--line); display:flex; gap:16px; align-items:baseline; flex-wrap:wrap; } | ||
| 176 | h1 { font-size:18px; margin:0; } | ||
| 177 | h2 { font-size:16px; } | ||
| 178 | .mut { color:var(--mut); } | ||
| 179 | .wrap { padding:16px 24px; max-width:1100px; margin:0 auto; } | ||
| 180 | input { width:100%; max-width:420px; padding:9px 12px; border:1px solid var(--line); border-radius:8px; background:var(--card); color:var(--fg); font-size:14px; } | ||
| 181 | table { width:100%; border-collapse:collapse; margin-top:12px; } | ||
| 182 | th,td { text-align:left; padding:9px 10px; border-bottom:1px solid var(--line); font-variant-numeric:tabular-nums; } | ||
| 183 | th { font-size:12px; text-transform:uppercase; letter-spacing:.05em; color:var(--mut); } | ||
| 184 | tr.blk { cursor:pointer; } | ||
| 185 | tr.blk:hover td { background:var(--card); } | ||
| 186 | code { font-size:12px; word-break:break-all; } | ||
| 187 | .scroll { overflow-x:auto; } | ||
| 188 | .card { border:1px solid var(--line); border-radius:10px; background:var(--card); padding:14px 16px; margin-top:12px; } | ||
| 189 | .kv { display:grid; grid-template-columns:150px 1fr; gap:4px 12px; font-size:13px; } | ||
| 190 | .kv div:nth-child(odd){ color:var(--mut); } | ||
| 191 | .tx { border-top:1px solid var(--line); padding:10px 0; } | ||
| 192 | .io { display:grid; grid-template-columns:1fr 1fr; gap:16px; } | ||
| 193 | @media (max-width:640px){ .io{ grid-template-columns:1fr; } .kv{ grid-template-columns:110px 1fr; } } | ||
| 194 | .pill { display:inline-block; font-size:11px; padding:1px 7px; border-radius:99px; border:1px solid var(--line); color:var(--mut); } | ||
| 195 | button.link { background:none; border:none; color:var(--acc); cursor:pointer; font:inherit; padding:0; } | ||
| 196 | .note { color:var(--mut); font-size:13px; max-width:820px; } | ||
| 197 | </style> | ||
| 198 | </head> | 180 | </head> |
| 199 | <body> | 181 | <body> |
| 200 | <header> | 182 | <header class="topbar"> |
| 201 | <h1>Bitflash Block Explorer</h1> | 183 | <a class="brand" href="https://bitflash.network/"><img src="logo.png" width="22" height="22" alt="">Bitflash</a> |
| 202 | <span class="mut" id="tip"></span> | 184 | <nav aria-label="Bitflash sites"> |
| 203 | <span style="flex:1"></span> | 185 | <a href="https://bitflash.network/">home</a> |
| 204 | <button class="link" id="home" style="display:none">back to blocks</button> | 186 | <a href="https://git.bitflash.network/bitflash/bitflash">code</a> |
| 187 | <a href="https://docs.bitflash.network/">docs</a> | ||
| 188 | <a href="https://releases.bitflash.network/">downloads</a> | ||
| 189 | <a href="https://explorer.bitflash.network/" aria-current="page">explorer</a> | ||
| 190 | <a href="https://status.bitflash.network/">status</a> | ||
| 191 | </nav> | ||
| 192 | <span class="meta" id="tip"></span> | ||
| 205 | </header> | 193 | </header> |
| 206 | <div class="wrap"> | 194 | <div class="wrap"> |
| 195 | <h1>Block explorer <button class="link" id="home" hidden>back to blocks</button></h1> | ||
| 207 | <p class="note">Read-only view of the main chain: blocks, their transactions, and the coinbase payout. There is no mempool and no per-address history here.</p> | 196 | <p class="note">Read-only view of the main chain: blocks, their transactions, and the coinbase payout. There is no mempool and no per-address history here.</p> |
| 208 | <div id="listview"> | 197 | <div id="listview"> |
| 209 | <input id="q" placeholder="Search by height or block hash"> | 198 | <input id="q" placeholder="Search by height or block hash"> |
| @@ -213,9 +202,63 @@ INDEX_HTML = r"""<!doctype html> | |||
| 213 | </table></div> | 202 | </table></div> |
| 214 | <p class="mut" id="more"></p> | 203 | <p class="mut" id="more"></p> |
| 215 | </div> | 204 | </div> |
| 216 | <div id="detail" style="display:none"></div> | 205 | <div id="detail" hidden></div> |
| 217 | </div> | 206 | </div> |
| 218 | <script> | 207 | </body> |
| 208 | </html> | ||
| 209 | """ | ||
| 210 | |||
| 211 | |||
| 212 | STYLE_CSS = r""":root{ | ||
| 213 | color-scheme: light dark; | ||
| 214 | --bg:#fff; --bg-2:#f6f6f6; --fg:#111; --dim:#6b6b6b; --line:#d7d7d7; --line-hard:#111; | ||
| 215 | --accent:#0b7a34; --accent-2:#12a047; --bar:3rem; | ||
| 216 | --mono: ui-monospace,"Cascadia Mono","Segoe UI Mono",Consolas,"DejaVu Sans Mono","Liberation Mono","Courier New",monospace; | ||
| 217 | } | ||
| 218 | @media (prefers-color-scheme: dark){:root{ | ||
| 219 | --bg:#000; --bg-2:#0b0b0b; --fg:#dcdcdc; --dim:#8a8a8a; --line:#242424; --line-hard:#4a4a4a; | ||
| 220 | --accent:#2ee06a; --accent-2:#6bff9f; | ||
| 221 | }} | ||
| 222 | *{box-sizing:border-box;} | ||
| 223 | html,body{margin:0;background:var(--bg);color:var(--fg);font:15px/1.55 var(--mono);-webkit-text-size-adjust:100%;} | ||
| 224 | a{color:var(--accent);} | ||
| 225 | .topbar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;min-height:var(--bar); | ||
| 226 | padding:.5rem clamp(.9rem,2.5vw,3rem);border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:5;} | ||
| 227 | .brand{display:flex;align-items:center;gap:.6rem;text-decoration:none;color:var(--fg);font-weight:bold;} | ||
| 228 | .brand img{width:22px;height:22px;display:block;} | ||
| 229 | .topbar nav{display:flex;flex-wrap:wrap;gap:.15rem 1.4rem;font-size:.86rem;} | ||
| 230 | .topbar nav a{text-decoration:none;color:var(--dim);} | ||
| 231 | .topbar nav a::before{content:"/";color:var(--line-hard);margin-right:.3rem;} | ||
| 232 | .topbar nav a:hover{color:var(--fg);text-decoration:underline;} | ||
| 233 | .topbar nav a[aria-current="page"]{color:var(--accent);font-weight:bold;} | ||
| 234 | .topbar nav a[aria-current="page"]::before{color:var(--accent);} | ||
| 235 | .topbar .meta{margin-left:auto;font-size:.76rem;color:var(--dim);letter-spacing:.06em;} | ||
| 236 | .wrap{padding:1.4rem clamp(.9rem,2.5vw,3rem) 4rem;} | ||
| 237 | h1{font-size:1rem;margin:0 0 .3rem;letter-spacing:.02em;} | ||
| 238 | h2{font-size:.95rem;margin:1.2rem 0 .4rem;} | ||
| 239 | .mut{color:var(--dim);} | ||
| 240 | .note{color:var(--dim);font-size:.82rem;max-width:60rem;margin:.2rem 0 1rem;} | ||
| 241 | input{width:100%;max-width:28rem;padding:.5rem .7rem;border:1px solid var(--line);background:var(--bg-2);color:var(--fg);font:inherit;font-size:.86rem;} | ||
| 242 | input:focus{outline:none;border-color:var(--accent);} | ||
| 243 | .scroll{overflow-x:auto;} | ||
| 244 | table{width:100%;border-collapse:collapse;margin-top:.8rem;font-size:.86rem;} | ||
| 245 | th,td{text-align:left;padding:.5rem .6rem;border-bottom:1px solid var(--line);font-variant-numeric:tabular-nums;} | ||
| 246 | th{font-size:.72rem;text-transform:uppercase;letter-spacing:.1em;color:var(--dim);font-weight:normal;} | ||
| 247 | tr.blk{cursor:pointer;} | ||
| 248 | tr.blk:hover td{background:var(--bg-2);} | ||
| 249 | code{font-size:.8rem;word-break:break-all;color:var(--fg);} | ||
| 250 | .card{border:1px solid var(--line);background:var(--bg-2);padding:.9rem 1rem;margin-top:.8rem;} | ||
| 251 | .kv{display:grid;grid-template-columns:11rem 1fr;gap:.25rem .8rem;font-size:.82rem;} | ||
| 252 | .kv div:nth-child(odd){color:var(--dim);} | ||
| 253 | .tx{border-top:1px solid var(--line);padding:.7rem 0;} | ||
| 254 | .io{display:grid;grid-template-columns:1fr 1fr;gap:1rem;} | ||
| 255 | @media (max-width:640px){.io{grid-template-columns:1fr;}.kv{grid-template-columns:7rem 1fr;}.topbar .meta{margin-left:0;width:100%;}} | ||
| 256 | .pill{display:inline-block;font-size:.68rem;padding:.05rem .5rem;border:1px solid var(--line);color:var(--dim);text-transform:uppercase;letter-spacing:.05em;} | ||
| 257 | button.link{background:none;border:none;color:var(--accent);cursor:pointer;font:inherit;padding:0;text-decoration:underline;} | ||
| 258 | """ | ||
| 259 | |||
| 260 | |||
| 261 | EXPLORER_JS = r""" | ||
| 219 | var SUM = [], SHOWN = 200; | 262 | var SUM = [], SHOWN = 200; |
| 220 | function btf(sat){ return (sat/1e8).toFixed(8).replace(/0+$/,'').replace(/\.$/,'')+" BTF"; } | 263 | function btf(sat){ return (sat/1e8).toFixed(8).replace(/0+$/,'').replace(/\.$/,'')+" BTF"; } |
| 221 | function ts(t){ return new Date(t*1000).toISOString().replace('T',' ').replace('.000Z',' UTC'); } | 264 | function ts(t){ return new Date(t*1000).toISOString().replace('T',' ').replace('.000Z',' UTC'); } |
| @@ -310,25 +353,22 @@ function openBlock(h){ | |||
| 310 | })); | 353 | })); |
| 311 | append(tx, head, io); append(detail, tx); | 354 | append(tx, head, io); append(detail, tx); |
| 312 | }); | 355 | }); |
| 313 | document.getElementById('listview').style.display='none'; | 356 | document.getElementById('listview').hidden = true; |
| 314 | detail.style.display='block'; | 357 | detail.hidden = false; |
| 315 | document.getElementById('home').style.display='inline'; | 358 | document.getElementById('home').hidden = false; |
| 316 | window.scrollTo(0,0); | 359 | window.scrollTo(0,0); |
| 317 | }); | 360 | }); |
| 318 | } | 361 | } |
| 319 | document.getElementById('home').onclick=function(){ | 362 | document.getElementById('home').onclick=function(){ |
| 320 | document.getElementById('detail').style.display='none'; | 363 | document.getElementById('detail').hidden = true; |
| 321 | document.getElementById('listview').style.display='block'; | 364 | document.getElementById('listview').hidden = false; |
| 322 | this.style.display='none'; | 365 | this.hidden = true; |
| 323 | }; | 366 | }; |
| 324 | document.getElementById('q').oninput=function(){ renderList(this.value); }; | 367 | document.getElementById('q').oninput=function(){ renderList(this.value); }; |
| 325 | fetch('blocks.json').then(function(r){return r.json();}).then(function(d){ | 368 | fetch('blocks.json').then(function(r){return r.json();}).then(function(d){ |
| 326 | SUM=d.blocks; document.getElementById('tip').textContent='tip height '+d.tipHeight+' - '+d.count+' blocks'; | 369 | SUM=d.blocks; document.getElementById('tip').textContent='tip height '+d.tipHeight+' - '+d.count+' blocks'; |
| 327 | renderList(''); | 370 | renderList(''); |
| 328 | }); | 371 | }); |
| 329 | </script> | ||
| 330 | </body> | ||
| 331 | </html> | ||
| 332 | """ | 372 | """ |
| 333 | 373 | ||
| 334 | 374 | ||