Phone-run fixes: hash tokens, embed wakes on tab focus, dry faucet leaves drips due (+admin retry), short drip status, claim box wraps; one drip per wallet per mission
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Admin · PolHunter</title>
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
<link rel="stylesheet" href="/style.css?v=2">
|
||||
<link rel="stylesheet" href="/style.css?v=3">
|
||||
<style>
|
||||
label{display:block;font-size:12px;color:var(--dim);letter-spacing:.08em;text-transform:uppercase;margin:10px 0 4px}
|
||||
input,textarea,select{width:100%;padding:10px 12px;border-radius:10px;border:1px solid var(--edge);background:rgba(0,0,0,.35);color:var(--ink);font:14px var(--font)}
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Your board · PolHunter</title>
|
||||
<meta name="robots" content="noindex">
|
||||
<link rel="stylesheet" href="/style.css?v=2">
|
||||
<link rel="stylesheet" href="/style.css?v=3">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
@@ -29,6 +29,6 @@
|
||||
|
||||
<footer class="foot">Rewards are for completed missions, not income. The daily pool is limited; a find made after it is spent queues and pays next. Cryptocurrency involves risk of loss.</footer>
|
||||
</div>
|
||||
<script src="/app.js?v=2"></script>
|
||||
<script src="/app.js?v=3"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@
|
||||
const r = board.missions[0] && board.missions[0].reward;
|
||||
if (r) $('rangeLine').textContent = 'Each find pays a random drip between ' + r.minPol + ' and ' + r.maxPol + ' POL. Your codes are yours alone.';
|
||||
$('missions').innerHTML = board.missions.length ? board.missions.map(card).join('') : '<div class="card"><p>No missions are open right now. Check back soon.</p></div>';
|
||||
$('mine').innerHTML = board.drips.length ? board.drips.map(d => '<div class="row"><span>' + esc(d.site) + '</span><span class="site">' + ({ paid: 'paid', sent: 'sending', due: 'paying next', queued: 'queued for the next pool', failed: 'failed: ' + esc(d.error || '') }[d.status] || d.status) + '</span><span class="pol">+' + d.pol + ' POL</span>' + (d.tx ? '<a class="when" target="_blank" rel="noopener" href="' + explorer + '/tx/' + d.tx + '">verify ↗</a>' : '<span class="when"></span>') + '</div>').join('')
|
||||
$('mine').innerHTML = board.drips.length ? board.drips.map(d => '<div class="row"><span>' + esc(d.site) + '</span><span class="site">' + ({ paid: 'paid', sent: 'sending', due: 'paying next', queued: 'queued for the next pool', failed: 'held, being looked at' }[d.status] || d.status) + '</span><span class="pol">+' + d.pol + ' POL</span>' + (d.tx ? '<a class="when" target="_blank" rel="noopener" href="' + explorer + '/tx/' + d.tx + '">verify ↗</a>' : '<span class="when"></span>') + '</div>').join('')
|
||||
: '<div class="row"><span class="site">Nothing yet. Your first find goes here.</span></div>';
|
||||
document.querySelectorAll('[data-start]').forEach(b => b.addEventListener('click', () => start(b.dataset.start)));
|
||||
const s = $('submit'); if (s) { s.addEventListener('click', submit); $('code').addEventListener('keydown', e => { if (e.key === 'Enter') submit(); }); tick(); }
|
||||
@@ -43,7 +43,7 @@
|
||||
function tick() {
|
||||
const el = $('timer'); if (!el || !open) return;
|
||||
const left = Math.max(0, open.dwell - Math.floor((Date.now() - open.started) / 1000));
|
||||
el.innerHTML = left > 0 ? 'Your code appears on the site in about <b>' + left + 's</b>. Keep that tab open, then come back and type it here.' : 'Your code should be showing on the site now. Type it here.';
|
||||
el.innerHTML = left > 0 ? 'Your code appears on the site in about <b>' + left + 's</b>. <b>Stay on the site tab</b> until it shows (switching away pauses it), then come back and type it here.' : 'Your code should be showing on the site now. If it is not, switch to the site tab and give it a few seconds. Then type it here.';
|
||||
if (open.expires && Date.now() > open.expires) { el.innerHTML = 'This attempt timed out. Start the mission again.'; return; }
|
||||
setTimeout(tick, 1000);
|
||||
}
|
||||
|
||||
+10
-7
@@ -10,8 +10,9 @@
|
||||
(function () {
|
||||
var API = 'https://polhunter.com';
|
||||
try {
|
||||
var q = new URLSearchParams(location.search), t = q.get('ph');
|
||||
if (t) { sessionStorage.setItem('ph.token', t); q.delete('ph'); history.replaceState(null, '', location.pathname + (q.toString() ? '?' + q : '') + location.hash); }
|
||||
// the token arrives in the hash (#ph=) or, for older links, the query (?ph=); it is kept for this tab
|
||||
var h = new URLSearchParams((location.hash || '').replace(/^#/, '')), q = new URLSearchParams(location.search), t = h.get('ph') || q.get('ph');
|
||||
if (t) { sessionStorage.setItem('ph.token', t); h.delete('ph'); q.delete('ph'); history.replaceState(null, '', location.pathname + (q.toString() ? '?' + q : '') + (h.toString() ? '#' + h : '')); }
|
||||
t = sessionStorage.getItem('ph.token'); if (!t) return;
|
||||
} catch (e) { return; }
|
||||
// slots: explicit [data-ph-slot="i"] elements, or the i-th match of data-selector (e.g. ".video-card"
|
||||
@@ -30,14 +31,16 @@
|
||||
box.innerHTML = '<span style="width:22px;height:22px;border-radius:50%;background:radial-gradient(circle at 35% 35%,#c9a4ff,#8247e5 60%,#4b2a8c);box-shadow:0 0 14px rgba(130,71,229,.9);flex:none"></span><span>PolHunter code <b style="font-family:ui-monospace,Menlo,monospace;font-size:16px;letter-spacing:.14em;color:#f3be43">' + code + '</b></span>';
|
||||
el.appendChild(box);
|
||||
}
|
||||
var tries = 0;
|
||||
var tries = 0, pending = null, done = false;
|
||||
// phones freeze a background tab's timers: when the hunter comes back to this tab, ask right away
|
||||
document.addEventListener('visibilitychange', function () { if (document.visibilityState === 'visible' && !done) { clearTimeout(pending); ask(); } });
|
||||
function ask() {
|
||||
tries++; if (tries > 40) return;
|
||||
tries++; if (tries > 80 || done) return;
|
||||
fetch(API + '/api/embed/code?t=' + encodeURIComponent(t), { mode: 'cors', credentials: 'omit' }).then(function (r) { return r.json(); }).then(function (r) {
|
||||
if (r && r.code) { render(r.code, Number(r.slot) % slots); try { sessionStorage.removeItem('ph.token'); } catch (e) {} return; }
|
||||
if (r && r.wait) { setTimeout(ask, Math.min(r.wait, 10) * 1000); return; }
|
||||
if (r && r.code) { done = true; render(r.code, Number(r.slot) % slots); try { sessionStorage.removeItem('ph.token'); } catch (e) {} return; }
|
||||
if (r && r.wait) { pending = setTimeout(ask, Math.min(r.wait, 5) * 1000); return; }
|
||||
// expired / gone / wrong origin: say nothing
|
||||
}).catch(function () { setTimeout(ask, 8000); });
|
||||
}).catch(function () { pending = setTimeout(ask, 6000); });
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ask); else ask();
|
||||
})();
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>PolHunter</title>
|
||||
<meta name="description" content="Missions across the network. Visit a site, find the thing, get a drip of POL to your wallet.">
|
||||
<link rel="stylesheet" href="/style.css?v=2">
|
||||
<link rel="stylesheet" href="/style.css?v=3">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
|
||||
+3
-2
@@ -66,9 +66,10 @@ a{color:var(--pol-hi);text-decoration:none} a:hover{color:var(--gold-hi)}
|
||||
/* mission flow */
|
||||
.mission-open{border-color:var(--edge-hi);box-shadow:0 0 0 1px rgba(180,140,255,.25),0 20px 60px rgba(130,71,229,.25)}
|
||||
.timer{font:500 13px var(--mono);color:var(--muted)} .timer b{color:var(--gold-hi)}
|
||||
.codebox{display:flex;gap:8px;margin-top:12px}
|
||||
.codebox input{flex:1;padding:12px 14px;border-radius:12px;border:1px solid var(--edge);background:rgba(0,0,0,.35);color:var(--ink);font:600 18px var(--mono);letter-spacing:.2em;text-transform:uppercase;outline:none}
|
||||
.codebox{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}
|
||||
.codebox input{flex:1 1 140px;min-width:0;padding:12px 14px;border-radius:12px;border:1px solid var(--edge);background:rgba(0,0,0,.35);color:var(--ink);font:600 18px var(--mono);letter-spacing:.2em;text-transform:uppercase;outline:none}
|
||||
.codebox input:focus{border-color:var(--edge-hi)}
|
||||
.codebox .btn{flex:0 0 auto}
|
||||
.msg{margin-top:10px;font-size:14px} .msg.ok{color:var(--ok)} .msg.bad{color:var(--bad)}
|
||||
.foot{padding:40px 0 30px;color:var(--dim);font-size:12.5px;line-height:1.7;border-top:1px solid var(--edge);margin-top:30px}
|
||||
.adslot{min-height:90px;display:flex;align-items:center;justify-content:center;margin:26px 0;color:var(--dim);font-size:12px}
|
||||
|
||||
Reference in New Issue
Block a user