forked from bitcoinafterlife/bal-welist-website
Compare commits
8 Commits
8a9b1b21d1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
e395da105e
|
|||
| 8c75e40edc | |||
| 97617cecad | |||
|
3dcd8227fa
|
|||
|
b50b9f5de9
|
|||
| 373580b356 | |||
| a6ea23ff5f | |||
| 40db9f36ab |
99
MOBILE-CHANGES.md
Normal file
99
MOBILE-CHANGES.md
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# Mobile readability fixes — `index.html`
|
||||||
|
|
||||||
|
Base: commit `3dcd822` (`bitcoinafterlife/bal-welist-website`, `main`).
|
||||||
|
|
||||||
|
**Scope:** header, filter bar and server list only. CSS-only — the JavaScript is
|
||||||
|
byte-for-byte unchanged. Desktop rendering is unaffected: every change sits
|
||||||
|
inside a `@media (max-width: ...)` block, except one line on `body` (item 7).
|
||||||
|
|
||||||
|
The "Add your Will Executor" panel, the invoice and the QR code were left
|
||||||
|
untouched on purpose, since payments are expected to be made from a desktop
|
||||||
|
browser.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Chain selector overflowed the viewport
|
||||||
|
|
||||||
|
**Before:** `.seg` was an `inline-flex` row of four buttons (Bitcoin, Testnet,
|
||||||
|
Testnet4, Regtest) with no wrapping — roughly 340px wide. On a 360–390px phone,
|
||||||
|
minus page padding, it pushed past the right edge and made the whole page scroll
|
||||||
|
horizontally.
|
||||||
|
|
||||||
|
**After:** below 600px the selector becomes a full-width 2×2 grid. Inner
|
||||||
|
dividers are recalculated with `:nth-child` so the borders stay correct in the
|
||||||
|
new arrangement.
|
||||||
|
|
||||||
|
## 2. Touch targets too small
|
||||||
|
|
||||||
|
Chain buttons were ~33px tall. Raised to `min-height: 44px` (the standard
|
||||||
|
minimum for a finger), applied to the chain buttons, the Tor toggle row and the
|
||||||
|
JSON link.
|
||||||
|
|
||||||
|
## 3. Nested scrolling in the server list
|
||||||
|
|
||||||
|
**Before:** `.mobile-list` carried `max-height: 350px; overflow: auto`, so on a
|
||||||
|
phone the list was a small window scrolling inside a page that also scrolls —
|
||||||
|
the two gestures fight each other.
|
||||||
|
|
||||||
|
**After:** the height cap is removed below 860px; the list flows with the page.
|
||||||
|
The desktop table (`.table-card`) keeps its 350px cap unchanged.
|
||||||
|
|
||||||
|
## 4. Long URLs broke out of the cards
|
||||||
|
|
||||||
|
Server URLs contain no spaces, so the browser cannot break them and they
|
||||||
|
overflowed the card. Added `overflow-wrap: anywhere`, plus `min-width: 0` on the
|
||||||
|
flex parent — without it a flex child defaults to `min-width: auto` and refuses
|
||||||
|
to shrink below its content width.
|
||||||
|
|
||||||
|
The JS truncation at 40 characters is unchanged.
|
||||||
|
|
||||||
|
## 5. Uneven card grid
|
||||||
|
|
||||||
|
The five fields (Score, Wins, Fee, Version, Height) sat in two fixed columns,
|
||||||
|
leaving Height alone on a half-empty row. Switched to
|
||||||
|
`repeat(auto-fit, minmax(84px, 1fr))`, which fits as many columns as the width
|
||||||
|
allows.
|
||||||
|
|
||||||
|
## 6. iOS auto-zoom on the search field
|
||||||
|
|
||||||
|
iOS Safari zooms the entire page when a focused input has a font size below
|
||||||
|
16px, and the user then has to pinch back out. The filter field is raised to
|
||||||
|
16px below 600px and made full width.
|
||||||
|
|
||||||
|
## 7. Text inflation in landscape
|
||||||
|
|
||||||
|
Added `-webkit-text-size-adjust: 100%` to `body`. iOS enlarges font sizes when a
|
||||||
|
phone is rotated to landscape, which distorted the header and the cards. This is
|
||||||
|
the only change outside a media query; it has no effect on desktop browsers.
|
||||||
|
|
||||||
|
## 8. Tighter spacing below 480px
|
||||||
|
|
||||||
|
New breakpoint reducing padding and type size where space is scarce:
|
||||||
|
|
||||||
|
| Element | Before | After |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `.wrap` side padding | 20px | 14px (+12px usable width per row) |
|
||||||
|
| `header.hero` padding | 48px 0 28px | 28px 0 20px |
|
||||||
|
| `.brand h1` | 24px | 20px |
|
||||||
|
| Logo mark | 46px | 40px |
|
||||||
|
| `.stat .n` | 26px | 22px |
|
||||||
|
| `.intro-card` padding | 28px 32px | 20px 18px |
|
||||||
|
| `.info-block` padding | 22px 24px | 18px 16px |
|
||||||
|
| `.srv` padding | 16px | 14px |
|
||||||
|
| Footer | space-between, wrapping | single column |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification performed
|
||||||
|
|
||||||
|
- CSS braces balanced (148 open / 148 close).
|
||||||
|
- All 32 element IDs referenced by the JavaScript still present in the markup.
|
||||||
|
- Tag balance checked for `div`, `section`, `header`, `footer`, `main`, `table`,
|
||||||
|
`style`, `script`.
|
||||||
|
- Media queries present in order: 860px, 600px, 480px, `prefers-reduced-motion`.
|
||||||
|
|
||||||
|
## Not yet verified
|
||||||
|
|
||||||
|
Rendering was not tested on a physical device. Worth a quick check on one iPhone
|
||||||
|
and one Android phone before merging, in particular the 2×2 chain selector at
|
||||||
|
320px width (iPhone SE, the narrowest screen still in common use).
|
||||||
131
index.html
131
index.html
@@ -40,6 +40,10 @@ body{
|
|||||||
font-family:var(--body);
|
font-family:var(--body);
|
||||||
line-height:1.5;
|
line-height:1.5;
|
||||||
-webkit-font-smoothing:antialiased;
|
-webkit-font-smoothing:antialiased;
|
||||||
|
/* WHY: iOS Safari inflates font sizes when a phone is rotated to landscape,
|
||||||
|
which breaks the header and the server cards. Locking the adjustment to
|
||||||
|
100% keeps the layout identical in both orientations. No effect on desktop. */
|
||||||
|
-webkit-text-size-adjust:100%;
|
||||||
}
|
}
|
||||||
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 20px}
|
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 20px}
|
||||||
|
|
||||||
@@ -140,6 +144,12 @@ tbody tr:hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}
|
|||||||
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
|
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
|
||||||
.note{font-size:13px;color:var(--muted);margin-top:16px;line-height:1.55}
|
.note{font-size:13px;color:var(--muted);margin-top:16px;line-height:1.55}
|
||||||
.note strong{color:var(--ink)}
|
.note strong{color:var(--ink)}
|
||||||
|
.freshness-note{
|
||||||
|
font-size:12px;line-height:1.4;color:var(--muted);
|
||||||
|
background:var(--accent-soft);border:1px solid var(--line);border-radius:8px;
|
||||||
|
padding:7px 12px;margin:0 0 12px;
|
||||||
|
}
|
||||||
|
.freshness-note strong{color:var(--ink)}
|
||||||
.btn-share{
|
.btn-share{
|
||||||
display:block;margin:0 auto 8px;font:inherit;font-size:13px;cursor:pointer;
|
display:block;margin:0 auto 8px;font:inherit;font-size:13px;cursor:pointer;
|
||||||
padding:8px 16px;border-radius:8px;border:1px solid var(--line-strong);
|
padding:8px 16px;border-radius:8px;border:1px solid var(--line-strong);
|
||||||
@@ -182,6 +192,9 @@ tbody tr:hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}
|
|||||||
.intro-card h2{font-family:var(--display);font-size:24px;margin:0 0 10px;letter-spacing:-.01em}
|
.intro-card h2{font-family:var(--display);font-size:24px;margin:0 0 10px;letter-spacing:-.01em}
|
||||||
.intro-card p{margin:0;color:var(--muted);font-size:15px;line-height:1.65;max-width:820px}
|
.intro-card p{margin:0;color:var(--muted);font-size:15px;line-height:1.65;max-width:820px}
|
||||||
|
|
||||||
|
.fee-disclaimer{margin:12px 0 0;color:var(--muted);font-size:13px;line-height:1.5;font-style:italic}
|
||||||
|
.fee-disclaimer a{color:var(--accent)}
|
||||||
|
|
||||||
.info-section{margin:48px 0}
|
.info-section{margin:48px 0}
|
||||||
.info-section h2{font-family:var(--display);font-size:22px;margin:0 0 8px}
|
.info-section h2{font-family:var(--display);font-size:22px;margin:0 0 8px}
|
||||||
.info-section .sub{color:var(--muted);font-size:15px;line-height:1.6;margin:0 0 28px;max-width:760px}
|
.info-section .sub{color:var(--muted);font-size:15px;line-height:1.6;margin:0 0 28px;max-width:760px}
|
||||||
@@ -198,7 +211,11 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
.mobile-list{display:none}
|
.mobile-list{display:none}
|
||||||
@media (max-width:860px){
|
@media (max-width:860px){
|
||||||
.table-card{display:none}
|
.table-card{display:none}
|
||||||
.mobile-list{display:grid;gap:12px;max-height:350px;overflow:auto;padding-right:2px}
|
/* WHY: the previous "max-height:350px;overflow:auto" turned the server list
|
||||||
|
into a small scrollable window nested inside the page. On a touch screen
|
||||||
|
that inner scroll competes with the normal page scroll and makes the list
|
||||||
|
hard to read. On mobile the list now flows naturally with the page. */
|
||||||
|
.mobile-list{display:grid;gap:12px}
|
||||||
.add-grid{grid-template-columns:1fr}
|
.add-grid{grid-template-columns:1fr}
|
||||||
.info-grid{grid-template-columns:1fr}
|
.info-grid{grid-template-columns:1fr}
|
||||||
.hero-stats{gap:20px}
|
.hero-stats{gap:20px}
|
||||||
@@ -206,9 +223,82 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
.srv{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px;box-shadow:var(--shadow)}
|
.srv{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px;box-shadow:var(--shadow)}
|
||||||
.srv .top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:12px}
|
.srv .top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:12px}
|
||||||
.srv .rk{font-family:var(--display);font-weight:600;color:var(--rank);font-size:18px}
|
.srv .rk{font-family:var(--display);font-weight:600;color:var(--rank);font-size:18px}
|
||||||
.srv .grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;font-size:13px}
|
/* WHY: server URLs have no spaces, so a long URL cannot break by itself and
|
||||||
|
would overflow the card. "anywhere" lets it wrap at any character.
|
||||||
|
"min-width:0" is required because a flex child defaults to min-width:auto,
|
||||||
|
which prevents it from shrinking below its content width. */
|
||||||
|
.srv .top>div{min-width:0}
|
||||||
|
.srv .top a{display:inline-block;max-width:100%;overflow-wrap:anywhere}
|
||||||
|
/* WHY: with two fixed columns the fifth field (Height) was left alone on a
|
||||||
|
half-empty row. auto-fit fills the available width with as many columns as
|
||||||
|
fit, so the five fields always line up tidily. */
|
||||||
|
.srv .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(84px,1fr));gap:10px;font-size:13px}
|
||||||
.srv .grid div span{display:block;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
|
.srv .grid div span{display:block;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
|
||||||
.srv .grid div b{font-family:var(--mono);font-weight:600}
|
.srv .grid div b{font-family:var(--mono);font-weight:600;overflow-wrap:anywhere}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
Phone layout (<=600px).
|
||||||
|
Scope: header, filter bar and server list only. The "Add your Will Executor"
|
||||||
|
panel, the invoice and the QR code are intentionally left untouched, because
|
||||||
|
payments are expected to be made from a desktop browser.
|
||||||
|
--------------------------------------------------------------------------- */
|
||||||
|
@media (max-width:600px){
|
||||||
|
.controls{gap:10px}
|
||||||
|
|
||||||
|
/* WHY: the four chain buttons form a single non-wrapping row about 340px wide.
|
||||||
|
Inside a 360-390px phone screen (minus page padding) it overflowed the
|
||||||
|
viewport and produced horizontal scrolling. A 2x2 grid across the full
|
||||||
|
width removes the overflow. min-height:44px matches the recommended
|
||||||
|
minimum touch target size. */
|
||||||
|
.seg{display:grid;grid-template-columns:1fr 1fr;width:100%;border-radius:8px}
|
||||||
|
.seg button{font-size:14px;min-height:44px;padding:8px 10px;border-bottom:1px solid var(--line)}
|
||||||
|
.seg button:nth-child(2n){border-right:0} /* right column: no inner divider */
|
||||||
|
.seg button:nth-child(n+3){border-bottom:0} /* last row: no bottom divider */
|
||||||
|
|
||||||
|
/* Give the toggle and the JSON link a full-size touch area. */
|
||||||
|
.field{min-height:44px}
|
||||||
|
.btn-ghost{min-height:44px}
|
||||||
|
|
||||||
|
/* WHY: the search field takes the full width so it is comfortable to type in,
|
||||||
|
and the font is raised to 16px. Below 16px, iOS Safari automatically zooms
|
||||||
|
the whole page when the field receives focus, and the user then has to
|
||||||
|
pinch back out. 16px disables that behaviour. */
|
||||||
|
.search{flex:1 1 100%}
|
||||||
|
.search input{font-size:16px}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
Narrow phone layout (<=480px): tighter spacing to recover horizontal space.
|
||||||
|
--------------------------------------------------------------------------- */
|
||||||
|
@media (max-width:480px){
|
||||||
|
/* Recovers 12px of usable width on every row of the page. */
|
||||||
|
.wrap{padding:0 14px}
|
||||||
|
|
||||||
|
header.hero{padding:28px 0 20px}
|
||||||
|
.hero .wrap{gap:16px}
|
||||||
|
.brand{gap:12px}
|
||||||
|
.brand .mark{width:40px;height:40px;border-radius:10px}
|
||||||
|
.brand .mark .brand-logo{width:28px;height:28px}
|
||||||
|
.brand h1{font-size:20px}
|
||||||
|
.brand .sub{font-size:13px}
|
||||||
|
.stat .n{font-size:22px}
|
||||||
|
|
||||||
|
.controls{padding:16px 0 12px}
|
||||||
|
|
||||||
|
.srv{padding:14px}
|
||||||
|
|
||||||
|
.intro-card{padding:20px 18px;margin:22px 0 8px}
|
||||||
|
.intro-card h2{font-size:20px}
|
||||||
|
.intro-card p{font-size:14px}
|
||||||
|
|
||||||
|
.info-section{margin:32px 0}
|
||||||
|
.info-block{padding:18px 16px}
|
||||||
|
|
||||||
|
/* WHY: the four footer items were spread with space-between and wrapped into
|
||||||
|
an uneven, hard-to-read block. A single column reads cleanly on a phone. */
|
||||||
|
footer{margin-top:32px;padding:22px 0}
|
||||||
|
footer .wrap{flex-direction:column;gap:8px}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion:reduce){*{transition:none!important}}
|
@media (prefers-reduced-motion:reduce){*{transition:none!important}}
|
||||||
@@ -223,13 +313,12 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
<div class="mark"><svg class="brand-logo" viewBox="0 0 1036 1036" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Bitcoin After Life logo"><g transform="translate(0.000000,1036.000000) scale(0.100000,-0.100000)" fill="currentColor" stroke="none"><path d="M6130 10203 c-153 -318 -283 -665 -344 -916 -61 -250 -71 -335 -71 -602 1 -223 3 -249 28 -370 52 -244 140 -460 260 -633 72 -106 225 -257 320 -316 179 -111 335 -154 777 -211 232 -30 367 -61 442 -102 76 -41 195 -164 248 -257 170 -302 311 -774 362 -1211 19 -167 16 -591 -6 -745 -68 -484 -201 -871 -436 -1270 -541 -917 -1492 -1525 -2549 -1630 -132 -13 -453 -13 -596 0 -268 24 -530 77 -757 151 -1063 350 -1871 1192 -2187 2280 -63 217 -111 495 -127 742 -7 104 -7 107 -30 107 l-24 0 0 -167 c0 -286 27 -508 95 -773 148 -587 427 -1083 854 -1523 231 -237 423 -391 703 -563 685 -420 1543 -589 2343 -462 1346 213 2458 1211 2814 2524 89 329 116 543 115 919 0 349 -23 544 -100 847 -68 273 10 632 176 799 91 92 165 104 491 77 320 -26 499 36 699 242 171 175 285 422 320 690 15 116 12 401 -6 535 -13 100 -32 200 -91 478 -3 15 -8 27 -12 27 -3 0 -21 -30 -40 -66 -20 -39 -63 -96 -105 -139 -127 -130 -287 -216 -616 -330 -297 -104 -420 -161 -551 -256 -159 -117 -268 -285 -325 -504 -36 -135 -37 -312 -4 -500 12 -71 24 -132 26 -134 2 -2 41 33 87 78 115 115 199 177 369 270 267 146 442 260 590 384 38 32 72 57 74 54 7 -6 -107 -108 -193 -173 -88 -67 -259 -175 -402 -256 -58 -34 -146 -88 -196 -122 -107 -73 -276 -237 -332 -323 -50 -76 -100 -193 -116 -274 l-12 -60 -87 173 c-194 389 -411 680 -731 980 -375 353 -563 553 -677 723 -54 79 -170 297 -170 318 0 7 21 -22 46 -63 179 -288 481 -616 885 -962 265 -227 363 -338 496 -560 32 -54 60 -97 63 -98 9 0 100 229 141 352 99 302 114 589 44 869 -105 419 -325 659 -955 1039 -333 201 -500 322 -642 465 -148 150 -254 318 -297 475 -11 40 -22 75 -25 77 -2 2 -27 -44 -56 -104z"/><path d="M4436 9470 c-1069 -83 -2060 -527 -2825 -1265 -567 -548 -975 -1198 -1195 -1909 -248 -796 -290 -1575 -130 -2365 213 -1049 795 -2006 1636 -2688 727 -590 1604 -940 2558 -1023 189 -16 648 -14 825 5 601 63 1114 212 1645 481 834 421 1518 1083 1967 1904 296 540 464 1079 540 1725 23 203 23 683 -1 908 -39 374 -122 744 -237 1062 l-31 84 -151 -53 c-141 -49 -152 -54 -151 -77 1 -13 20 -94 42 -179 303 -1165 101 -2402 -553 -3395 -410 -622 -943 -1098 -1600 -1431 -469 -237 -913 -369 -1450 -430 -202 -24 -622 -24 -830 -1 -739 82 -1409 331 -1990 741 -293 206 -640 542 -869 840 -474 616 -756 1323 -843 2111 -20 185 -22 593 -4 785 112 1186 708 2250 1662 2965 619 465 1347 745 2139 826 127 13 546 18 745 9 l110 -5 21 160 c12 88 21 161 20 162 -4 4 -149 25 -275 39 -161 18 -620 26 -775 14z"/><path d="M3870 6492 c-52 -26 -73 -71 -78 -169 l-5 -83 -98 0 -99 0 0 -225 0 -225 100 0 100 0 0 -355 0 -355 -100 0 -100 0 0 -230 0 -230 100 0 100 0 0 -355 0 -355 -100 0 -100 0 0 -225 0 -225 100 0 100 0 0 -80 c0 -97 17 -142 62 -170 29 -17 50 -20 169 -20 125 0 139 2 170 23 43 29 58 71 58 170 l1 77 64 0 64 0 4 -111 c3 -107 4 -112 31 -135 27 -23 34 -24 182 -24 221 0 235 10 243 172 l5 98 261 0 c227 0 272 3 345 20 264 64 482 254 576 505 119 313 36 650 -216 878 l-72 64 33 47 c43 63 94 176 116 256 25 91 25 299 0 395 -59 230 -220 428 -431 530 -141 69 -182 77 -412 82 l-203 5 0 77 c0 104 -14 147 -53 171 -28 18 -51 20 -185 20 l-154 0 -34 -34 -34 -34 0 -101 0 -101 -65 0 -65 0 0 85 c0 162 -28 185 -222 185 -97 0 -130 -4 -158 -18z m1307 -732 c74 -45 103 -184 85 -416 -12 -151 -31 -208 -85 -248 -28 -21 -39 -21 -478 -24 l-449 -3 0 356 0 355 448 0 c426 0 448 -1 479 -20z m150 -1172 c46 -30 93 -97 125 -177 18 -45 22 -77 22 -161 1 -98 -1 -110 -30 -171 -35 -73 -92 -142 -135 -165 -23 -12 -115 -14 -544 -14 l-515 0 0 360 0 360 518 -3 518 -2 41 -27z"/></g></svg></div>
|
<div class="mark"><svg class="brand-logo" viewBox="0 0 1036 1036" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Bitcoin After Life logo"><g transform="translate(0.000000,1036.000000) scale(0.100000,-0.100000)" fill="currentColor" stroke="none"><path d="M6130 10203 c-153 -318 -283 -665 -344 -916 -61 -250 -71 -335 -71 -602 1 -223 3 -249 28 -370 52 -244 140 -460 260 -633 72 -106 225 -257 320 -316 179 -111 335 -154 777 -211 232 -30 367 -61 442 -102 76 -41 195 -164 248 -257 170 -302 311 -774 362 -1211 19 -167 16 -591 -6 -745 -68 -484 -201 -871 -436 -1270 -541 -917 -1492 -1525 -2549 -1630 -132 -13 -453 -13 -596 0 -268 24 -530 77 -757 151 -1063 350 -1871 1192 -2187 2280 -63 217 -111 495 -127 742 -7 104 -7 107 -30 107 l-24 0 0 -167 c0 -286 27 -508 95 -773 148 -587 427 -1083 854 -1523 231 -237 423 -391 703 -563 685 -420 1543 -589 2343 -462 1346 213 2458 1211 2814 2524 89 329 116 543 115 919 0 349 -23 544 -100 847 -68 273 10 632 176 799 91 92 165 104 491 77 320 -26 499 36 699 242 171 175 285 422 320 690 15 116 12 401 -6 535 -13 100 -32 200 -91 478 -3 15 -8 27 -12 27 -3 0 -21 -30 -40 -66 -20 -39 -63 -96 -105 -139 -127 -130 -287 -216 -616 -330 -297 -104 -420 -161 -551 -256 -159 -117 -268 -285 -325 -504 -36 -135 -37 -312 -4 -500 12 -71 24 -132 26 -134 2 -2 41 33 87 78 115 115 199 177 369 270 267 146 442 260 590 384 38 32 72 57 74 54 7 -6 -107 -108 -193 -173 -88 -67 -259 -175 -402 -256 -58 -34 -146 -88 -196 -122 -107 -73 -276 -237 -332 -323 -50 -76 -100 -193 -116 -274 l-12 -60 -87 173 c-194 389 -411 680 -731 980 -375 353 -563 553 -677 723 -54 79 -170 297 -170 318 0 7 21 -22 46 -63 179 -288 481 -616 885 -962 265 -227 363 -338 496 -560 32 -54 60 -97 63 -98 9 0 100 229 141 352 99 302 114 589 44 869 -105 419 -325 659 -955 1039 -333 201 -500 322 -642 465 -148 150 -254 318 -297 475 -11 40 -22 75 -25 77 -2 2 -27 -44 -56 -104z"/><path d="M4436 9470 c-1069 -83 -2060 -527 -2825 -1265 -567 -548 -975 -1198 -1195 -1909 -248 -796 -290 -1575 -130 -2365 213 -1049 795 -2006 1636 -2688 727 -590 1604 -940 2558 -1023 189 -16 648 -14 825 5 601 63 1114 212 1645 481 834 421 1518 1083 1967 1904 296 540 464 1079 540 1725 23 203 23 683 -1 908 -39 374 -122 744 -237 1062 l-31 84 -151 -53 c-141 -49 -152 -54 -151 -77 1 -13 20 -94 42 -179 303 -1165 101 -2402 -553 -3395 -410 -622 -943 -1098 -1600 -1431 -469 -237 -913 -369 -1450 -430 -202 -24 -622 -24 -830 -1 -739 82 -1409 331 -1990 741 -293 206 -640 542 -869 840 -474 616 -756 1323 -843 2111 -20 185 -22 593 -4 785 112 1186 708 2250 1662 2965 619 465 1347 745 2139 826 127 13 546 18 745 9 l110 -5 21 160 c12 88 21 161 20 162 -4 4 -149 25 -275 39 -161 18 -620 26 -775 14z"/><path d="M3870 6492 c-52 -26 -73 -71 -78 -169 l-5 -83 -98 0 -99 0 0 -225 0 -225 100 0 100 0 0 -355 0 -355 -100 0 -100 0 0 -230 0 -230 100 0 100 0 0 -355 0 -355 -100 0 -100 0 0 -225 0 -225 100 0 100 0 0 -80 c0 -97 17 -142 62 -170 29 -17 50 -20 169 -20 125 0 139 2 170 23 43 29 58 71 58 170 l1 77 64 0 64 0 4 -111 c3 -107 4 -112 31 -135 27 -23 34 -24 182 -24 221 0 235 10 243 172 l5 98 261 0 c227 0 272 3 345 20 264 64 482 254 576 505 119 313 36 650 -216 878 l-72 64 33 47 c43 63 94 176 116 256 25 91 25 299 0 395 -59 230 -220 428 -431 530 -141 69 -182 77 -412 82 l-203 5 0 77 c0 104 -14 147 -53 171 -28 18 -51 20 -185 20 l-154 0 -34 -34 -34 -34 0 -101 0 -101 -65 0 -65 0 0 85 c0 162 -28 185 -222 185 -97 0 -130 -4 -158 -18z m1307 -732 c74 -45 103 -184 85 -416 -12 -151 -31 -208 -85 -248 -28 -21 -39 -21 -478 -24 l-449 -3 0 356 0 355 448 0 c426 0 448 -1 479 -20z m150 -1172 c46 -30 93 -97 125 -177 18 -45 22 -77 22 -161 1 -98 -1 -110 -30 -171 -35 -73 -92 -142 -135 -165 -23 -12 -115 -14 -544 -14 l-515 0 0 360 0 360 518 -3 518 -2 41 -27z"/></g></svg></div>
|
||||||
<div>
|
<div>
|
||||||
<h1>Will Executor — Server List</h1>
|
<h1>Will Executor — Server List</h1>
|
||||||
<div class="sub">Bitcoin After Life · Will-executor node leaderboard</div>
|
<div class="sub"><a href="https://bitcoin-after.life" target="_blank" rel="noopener">Bitcoin After Life</a> · Will-executor node leaderboard</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-stats">
|
<div class="hero-stats">
|
||||||
<div class="stat"><div class="n" id="s-online">0</div><div class="l">Online</div></div>
|
<div class="stat"><div class="n" id="s-online">0</div><div class="l">Online</div></div>
|
||||||
<div class="stat"><div class="n" id="s-total">0</div><div class="l">Servers</div></div>
|
<div class="stat"><div class="n" id="s-total">0</div><div class="l">Servers</div></div>
|
||||||
<div class="stat"><div class="n" id="s-block">—</div><div class="l">Block</div></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -259,15 +348,19 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
<a class="btn-ghost" id="download" href="#" download="willexecutors.json">↓ JSON</a>
|
<a class="btn-ghost" id="download" href="#" download="willexecutors.json">↓ JSON</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p class="freshness-note">
|
||||||
|
<strong>Fee/description/version</strong> refresh about once a day (timing varies). <strong>Deposits</strong> are credited instantly after 3 confirmations (~30 min).
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="table-card">
|
<div class="table-card">
|
||||||
<table id="tbl">
|
<table id="tbl">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="num">#</th>
|
<th class="num">#</th>
|
||||||
<th>URL</th>
|
<th>URL</th>
|
||||||
<th>Info</th>
|
<th>Info*</th>
|
||||||
<th class="num">Fee</th>
|
<th class="num">Fee*</th>
|
||||||
<th>Version</th>
|
<th>Version*</th>
|
||||||
<th class="num">Height</th>
|
<th class="num">Height</th>
|
||||||
<th class="num">Wins</th>
|
<th class="num">Wins</th>
|
||||||
<th class="num">Score</th>
|
<th class="num">Score</th>
|
||||||
@@ -279,6 +372,8 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
|
|
||||||
<div class="mobile-list" id="mlist"></div>
|
<div class="mobile-list" id="mlist"></div>
|
||||||
|
|
||||||
|
<p class="fee-disclaimer">* Info, Fee and Version data may not reflect actual values or may be outdated. Refer to the <a href="https://bitcoin-after.life" target="_blank" rel="noopener">Bitcoin After Life plugin</a> for up-to-date information.</p>
|
||||||
|
|
||||||
<section class="intro-card">
|
<section class="intro-card">
|
||||||
<h2>Will Executor Server List</h2>
|
<h2>Will Executor Server List</h2>
|
||||||
<p>This page displays all Will Executor servers that manage the inheritance processing for the Bitcoin After Life plugin on Electrum. Will Executors operate in a competitive environment, racing to broadcast inheritance transactions to network nodes and earn the associated transaction fees.</p>
|
<p>This page displays all Will Executor servers that manage the inheritance processing for the Bitcoin After Life plugin on Electrum. Will Executors operate in a competitive environment, racing to broadcast inheritance transactions to network nodes and earn the associated transaction fees.</p>
|
||||||
@@ -380,6 +475,13 @@ footer a{color:var(--accent);text-decoration:none}
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
if (window.location.hostname !== 'localhost') {
|
||||||
|
const regtestBtn = document.querySelector('#chainSeg [data-c="regtest"]');
|
||||||
|
if (regtestBtn) {
|
||||||
|
regtestBtn.style.display = 'none';
|
||||||
|
regtestBtn.setAttribute('aria-pressed', 'false');
|
||||||
|
}
|
||||||
|
}
|
||||||
let allServers = [];
|
let allServers = [];
|
||||||
let withTor = true, q = "";
|
let withTor = true, q = "";
|
||||||
let minAmount = 50000;
|
let minAmount = 50000;
|
||||||
@@ -441,9 +543,6 @@ function render() {
|
|||||||
const online = allServers.filter(d => d.status === "OK").length;
|
const online = allServers.filter(d => d.status === "OK").length;
|
||||||
document.getElementById('s-online').textContent = online;
|
document.getElementById('s-online').textContent = online;
|
||||||
document.getElementById('s-total').textContent = allServers.length;
|
document.getElementById('s-total').textContent = allServers.length;
|
||||||
// Highest known block across all servers (the list is ranked by fee/points, not by height)
|
|
||||||
const maxBlock = allServers.reduce((m, d) => Math.max(m, d.last_block || 0), 0);
|
|
||||||
document.getElementById('s-block').textContent = maxBlock ? fmt(maxBlock) : '—';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
@@ -451,10 +550,14 @@ async function fetchData() {
|
|||||||
const params = new URLSearchParams({ page: 0, limit: 100 });
|
const params = new URLSearchParams({ page: 0, limit: 100 });
|
||||||
if (!withTor) params.append("onion", "no");
|
if (!withTor) params.append("onion", "no");
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/data/${chain}?${params}`);
|
// NOTE: /data/{chain} returns a HashMap, whose JSON key order is not
|
||||||
|
// guaranteed (it can change on every backend restart). /datalist/{chain}
|
||||||
|
// returns an ordered array (Vec) that preserves the server-side sort
|
||||||
|
// (donation DESC, balance DESC, base_fee ASC, wetime_points DESC) — see terms.html §3.
|
||||||
|
const response = await fetch(`/datalist/${chain}?${params}`);
|
||||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||||
const obj = await response.json();
|
const list = await response.json();
|
||||||
allServers = Object.entries(obj).map(([key, s]) => ({ id: key, ...s }));
|
allServers = list;
|
||||||
render();
|
render();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Fetch error:', err);
|
console.error('Fetch error:', err);
|
||||||
|
|||||||
Reference in New Issue
Block a user