// OScope: page entry. Header, search, routes. import { $, h, usd, sol as fsol, short } from './util.js'; import { icon } from './icons.js'; import { live, net } from './net.js'; import { paper } from './paper.js'; import './trackers.js'; import { route, mount, go } from './router.js'; import { avatar } from './parts.js'; import { openSettings } from './settings.js'; import { pulseView } from './pulse.js'; import { liveView } from './live.js'; import { coinView } from './coin.js'; import { portfolioView } from './portfolio.js'; import { trackersView, walletView } from './trackerview.js'; route(/^\/$/, pulseView, 'pulse'); route(/^\/live$/, liveView, 'live'); route(/^\/coin\/([1-9A-HJ-NP-Za-km-z]{32,44})$/, coinView, ''); route(/^\/portfolio$/, portfolioView, 'portfolio'); route(/^\/trackers$/, trackersView, 'trackers'); route(/^\/wallet\/([1-9A-HJ-NP-Za-km-z]{32,44})$/, walletView, ''); // ---------- header ---------- $('.search-ic').innerHTML = icon('search', 15); $('.wallet-ic').innerHTML = icon('wallet', 15); $('#settings-btn').innerHTML = icon('gear', 17); $('#settings-btn').addEventListener('click', openSettings); function status() { const f = $('#feed'); const ok = live.open && live.feed && (live.lag == null || live.lag < 15000); f.className = 'feed ' + (ok ? 'ok' : live.open ? 'bad' : ''); $('#feed-txt').textContent = !live.open ? 'Connecting' : !live.feed ? 'Stream down' : live.lag > 15000 ? 'Stream quiet' : 'Live'; $('#solpx span').textContent = live.sol ? '$' + live.sol.toFixed(2) : '–'; } live.on('status', status); status(); function wallet() { $('#wallet-sol').textContent = fsol(paper.s.sol) + ' SOL'; } paper.on('change', wallet); wallet(); // ---------- search ---------- const q = $('#q'), res = $('#search-res'); let timer = 0, items = [], sel = -1, seq = 0; async function search() { const text = q.value.trim(); if (!text) { res.classList.remove('open'); return; } const my = ++seq; let list = []; try { list = await net.get('/api/search?q=' + encodeURIComponent(text)); } catch {} if (my !== seq) return; items = list; sel = list.length ? 0 : -1; const isAddr = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(text); res.replaceChildren(...(list.length ? list.map((r, i) => h('a.sr' + (i === sel ? '.sel' : ''), { href: `/coin/${r.m}`, 'data-link': '', onmousedown: e => e.preventDefault(), onclick: () => close() }, avatar(r, 36), h('div', { style: { minWidth: 0 } }, h('b', null, r.n || r.s), ' ', h('span.mut', null, r.s), h('div.mut', null, short(r.m, 5))), h('div', { style: { textAlign: 'right' } }, h('b', null, usd(r.mc * live.sol)), h('div.mut', null, r.mig ? 'Migrated' : r.pr.toFixed(0) + '% curve')))) : isAddr ? [h('a.sr', { href: `/coin/${text}`, 'data-link': '', onclick: () => close() }, h('div'), h('div', null, h('b', null, 'Open this coin'), h('div.mut', null, short(text, 6))), h('span')), h('a.sr', { href: `/wallet/${text}`, 'data-link': '', onclick: () => close() }, h('div'), h('div', null, h('b', null, 'Open as a wallet'), h('div.mut', null, short(text, 6))), h('span'))] : [h('div.sr-empty', null, 'No coin by that name in the last hours')])); res.classList.add('open'); } function close() { res.classList.remove('open'); q.value = ''; q.blur(); } q.addEventListener('input', () => { clearTimeout(timer); timer = setTimeout(search, 120); }); q.addEventListener('focus', () => { if (q.value.trim()) search(); }); q.addEventListener('blur', () => setTimeout(() => res.classList.remove('open'), 120)); q.addEventListener('keydown', e => { const links = [...res.querySelectorAll('a.sr')]; if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { e.preventDefault(); sel = Math.max(0, Math.min(links.length - 1, sel + (e.key === 'ArrowDown' ? 1 : -1))); links.forEach((a, i) => a.classList.toggle('sel', i === sel)); } else if (e.key === 'Enter') { const a = links[Math.max(0, sel)]; if (a) { go(a.getAttribute('href')); close(); } } else if (e.key === 'Escape') close(); }); document.addEventListener('keydown', e => { if (e.key === '/' && !/^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement?.tagName)) { e.preventDefault(); q.focus(); } }); mount();