miner-ui-4: live-dag.js from site-ui-3 6bc408b (wheel passes to the page until the scene is engaged); the engaged chip 'scroll to zoom · Esc to release' on the Overview
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
b371bf2bf4
commit
7996240f6f
4 changed files with 23 additions and 7 deletions
|
|
@ -634,6 +634,7 @@ body.drawer-open .toast{bottom:calc(var(--drawer-h) + 16px)}
|
|||
#dag{height:120px;margin-bottom:0}
|
||||
.dag-tip{position:absolute;left:0;top:0;pointer-events:none;background:var(--graphite);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;font-size:var(--t-xs);color:var(--ink-2);display:flex;flex-direction:column;gap:2px;max-width:320px;box-shadow:0 8px 24px var(--shadow);z-index:3}
|
||||
.dag-tip b{color:var(--bone);font-weight:500;word-break:break-all}
|
||||
.dag-chip{position:absolute;right:10px;top:10px;font-size:var(--t-xs);color:var(--ash);background:var(--graphite);border:1px solid var(--line-2);border-radius:999px;padding:3px 10px;pointer-events:none;z-index:2}
|
||||
.legend{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:var(--s-3);font-size:var(--t-sm);color:var(--ash);align-items:center}
|
||||
.legend span{display:inline-flex;align-items:center;gap:7px}
|
||||
.lg{width:10px;height:10px;border-radius:3px;display:inline-block;border:1.5px solid var(--ash);background:var(--row)}
|
||||
|
|
|
|||
|
|
@ -1318,7 +1318,7 @@ if (typeof document !== 'undefined') (function () {
|
|||
function mountDag() {
|
||||
if (dag || typeof IgneumDag === 'undefined' || !$('dag-live')) return;
|
||||
try {
|
||||
dag = IgneumDag.mount($('dag-live'), { compact: window.innerWidth < 720, window: 120, url: 'api/live', mine: 'you', tooltip: $('dag-tip'), pauseButton: $('dag-pause'), onState: function (st, why) {
|
||||
dag = IgneumDag.mount($('dag-live'), { compact: window.innerWidth < 720, window: 120, url: 'api/live', mine: 'you', tooltip: $('dag-tip'), chip: $('dag-chip'), pauseButton: $('dag-pause'), onState: function (st, why) {
|
||||
var live = st === 'live' || st === 'stale';
|
||||
if (dagMode !== st) { dagMode = st; setText('dag-state', st === 'live' ? 'live' : st === 'stale' ? 'behind' : st === 'failed' ? 'your blocks only' : 'connecting'); setText('dag-note', st === 'failed' ? 'The full chain view needs the next update. This is the last 10 minutes of your own blocks.' : st === 'stale' ? (why || '') : ''); }
|
||||
$('dag-live').hidden = !live; $('dag-tip').hidden = true; $('dag-pause').hidden = !live; $('dag').hidden = live;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@
|
|||
<div class="dag-wrap">
|
||||
<canvas id="dag-live" aria-label="The last two minutes of blocks: your row and the other miners, the selected chain as a lit path, checkpoints as bands"></canvas>
|
||||
<div class="dag-tip mono" id="dag-tip" hidden></div>
|
||||
<span class="dag-chip mono" id="dag-chip" hidden>scroll to zoom · Esc to release</span>
|
||||
<canvas id="dag" aria-hidden="true" hidden></canvas>
|
||||
</div>
|
||||
<div class="legend"><span><i class="lg you"></i>yours</span><span><i class="lg pending"></i>pending</span><span><i class="lg included"></i>included</span><span><i class="lg excluded"></i>excluded</span><span><i class="lg proven"></i>proven</span><span><i class="lg locked"></i>locked checkpoint</span><span class="dim" id="dag-note"></span></div>
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
are drawn; the edge between two selected-chain blocks is heavier and the chain glows as one path. Colour words are the
|
||||
ledger's: pending, included (blue), excluded (red), proven (every shard verified or paid), locked (a checkpoint block).
|
||||
Checkpoints are vertical bands at their blue score with the lock weight; a locked band is solid, a pending one dashed.
|
||||
The view scrolls at chain speed, new blocks arrive from the right with a brief glow; wheel and pinch zoom the window
|
||||
(30 to 300 s, the API's ?window=); a pause button; hover and tap show a block's details.
|
||||
The view scrolls at chain speed, new blocks arrive from the right with a brief glow. The page's scroll passes through the
|
||||
scene; zoom takes ctrl or cmd with the wheel, a pinch, or a click into the scene (engaged, released by Escape or a click
|
||||
outside; opts.chip is the "scroll to zoom, Esc to release" element); window 30 to 300 s (the API's ?window=); a pause button;
|
||||
hover and tap show a block's details.
|
||||
|
||||
Usage: var dag = IgneumDag.mount(canvas, { compact, window, url, poll, mine, onState, onData, onWindow, pauseButton, tooltip })
|
||||
Usage: var dag = IgneumDag.mount(canvas, { compact, window, url, poll, mine, onState, onData, onWindow, onEngage, pauseButton, tooltip, chip })
|
||||
- url: the /api/live endpoint (default '/api/live'); poll: false stops the module's own 2 s fetch, the host then calls
|
||||
dag.push(reply) with a reply of the same shape ({ok, state:{stale, age_s, height, ...}, blocks:[...], finality:{checkpoints:[...]}, proving})
|
||||
whenever it has new data (every poll or every new block, either is fine; blocks already on screen are updated in place).
|
||||
|
|
@ -196,8 +198,20 @@
|
|||
}
|
||||
canvas.addEventListener('mousemove', function (ev) { hover = hit(ev); canvas.style.cursor = hover ? 'pointer' : 'default'; if (!pinned) showTip(hover, ev); kick(); });
|
||||
canvas.addEventListener('mouseleave', function () { hover = null; if (!pinned) showTip(null); kick(); });
|
||||
canvas.addEventListener('click', function (ev) { var b = hit(ev); pinned = (pinned && b && pinned.hash === b.hash) ? null : b; showTip(pinned || hover); kick(); });
|
||||
canvas.addEventListener('wheel', function (ev) { if (!ev.ctrlKey && Math.abs(ev.deltaY) < 1) return; ev.preventDefault(); zoom(ev.deltaY > 0 ? 1.15 : 1 / 1.15); }, { passive: false });
|
||||
canvas.addEventListener('click', function (ev) { engage(true); var b = hit(ev); pinned = (pinned && b && pinned.hash === b.hash) ? null : b; showTip(pinned || hover); kick(); });
|
||||
// the wheel is never captured by default (6 Oct 2026, the project lead: scrolling past the scene zoomed it): the page scrolls through the
|
||||
// scene; zoom takes ctrl or cmd with the wheel, a pinch, or a click into the scene, which engages it (opts.chip shows
|
||||
// "scroll to zoom, Esc to release"); Escape, a click outside or leaving the scene releases it
|
||||
var engaged = false, chip = opts.chip || null;
|
||||
function engage(on) { if (on === engaged) return; engaged = on; canvas.classList.toggle('engaged', on); if (chip) chip.hidden = !on; if (opts.onEngage) opts.onEngage(on); }
|
||||
canvas.addEventListener('wheel', function (ev) {
|
||||
var zoomKey = ev.ctrlKey || ev.metaKey;
|
||||
if (!zoomKey && !engaged) return; // a plain wheel or a two-finger scroll passes through to the page
|
||||
if (Math.abs(ev.deltaY) < 1) return;
|
||||
ev.preventDefault(); zoom(ev.deltaY > 0 ? 1.15 : 1 / 1.15);
|
||||
}, { passive: false });
|
||||
document.addEventListener('keydown', function (ev) { if (ev.key === 'Escape' && engaged) engage(false); });
|
||||
document.addEventListener('pointerdown', function (ev) { if (engaged && !canvas.contains(ev.target) && !(chip && chip.contains(ev.target))) engage(false); });
|
||||
var pinch = null;
|
||||
canvas.addEventListener('touchstart', function (ev) { if (ev.touches.length === 2) pinch = dist(ev.touches); }, { passive: true });
|
||||
canvas.addEventListener('touchmove', function (ev) { if (ev.touches.length === 2 && pinch) { var d = dist(ev.touches); if (Math.abs(d - pinch) > 12) { zoom(d > pinch ? 1 / 1.1 : 1.1); pinch = d; } } }, { passive: true });
|
||||
|
|
@ -216,7 +230,7 @@
|
|||
new MutationObserver(function () { readTheme(); kick(); }).observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
||||
|
||||
readTheme(); size(); if (opts.poll !== false) { poll(); setInterval(poll, 2000); } kick();
|
||||
return { push: push, setPaused: setPaused, zoom: zoom, getWindow: function () { return windowS; }, getState: function () { return { state: state, reason: reason }; }, redraw: kick, words: words };
|
||||
return { push: push, setPaused: setPaused, zoom: zoom, engage: engage, getWindow: function () { return windowS; }, getState: function () { return { state: state, reason: reason }; }, redraw: kick, words: words };
|
||||
}
|
||||
root.IgneumDag = { mount: mount };
|
||||
})(window);
|
||||
|
|
|
|||
Loading…
Reference in a new issue