Back to OScope
oscope/public/js/parts.js
Code
65 lines (58 loc) · 2.63 KB
// Pieces several views draw the same way.
import { h, hue, safeHref } from './util.js';
import { icon, iconEl } from './icons.js';
export function avatar(c, size) {
const sym = (c.s || c.n || '?').replace(/^\$/, '');
const el = h('div.av', size ? { style: { width: size + 'px', height: size + 'px' } } : null);
const ph = h('div.ph', { style: { background: `linear-gradient(135deg, hsl(${hue(c.m || sym)} 45% 28%), hsl(${(hue(c.m || sym) + 40) % 360} 50% 16%))` } }, sym.slice(0, 2).toUpperCase());
el.append(ph);
if (c.img) setImg(el, c.img);
return el;
}
export function setImg(av, src) {
if (av.dataset.src === src) return;
av.dataset.src = src;
av.querySelector('img')?.remove();
const img = new Image();
img.decoding = 'async';
img.loading = 'lazy';
img.alt = '';
img.referrerPolicy = 'no-referrer';
img.onload = () => { img.classList.add('ok'); av.querySelector('.ph')?.remove(); };
// a picture that fails is asked for again at a later update, twice at most
img.onerror = () => { img.remove(); av._tries = (av._tries || 0) + 1; if (av._tries <= 2) setTimeout(() => { if (av.dataset.src === src) delete av.dataset.src; }, 8000); };
img.src = src;
av.append(img);
}
export function socials(c, size = 14) {
const box = h('div.soc');
const add = (href, ic, title) => {
const u = href && safeHref(href);
const a = h('a', { href: u || '#', target: '_blank', rel: 'noopener noreferrer', title, html: icon(ic, size), onclick: e => e.stopPropagation() });
if (!u) a.classList.add('off');
box.append(a);
};
add(c.tw, 'xlogo', 'X');
add(c.web, 'globe', 'Website');
add(c.tg, 'tg', 'Telegram');
add(`https://x.com/search?q=${encodeURIComponent(c.m)}&f=live`, 'search', 'Search the address on X');
return box;
}
// green when low, amber in between, red when high (for holder concentration numbers)
export function level(v, good, bad) {
if (!Number.isFinite(v) || v === 0) return '';
return v <= good ? 'lv-g' : v >= bad ? 'lv-b' : 'lv-m';
}
export function chip(ic, text, cls = '', title = '') {
const el = h('span.chip' + (cls ? '.' + cls : ''), { title });
el.append(iconEl(ic, 12), document.createTextNode(text));
return el;
}
export function traceSvg() {
const t = document.createElement('template');
t.innerHTML = '<svg class="trace" viewBox="0 0 120 32" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 18h22l6-12 9 22 7-16 5 6h12l5-8 6 14 5-6h39"/></svg>';
return t.content.firstChild;
}
export function emptyState(title, text) {
return h('div.empty', null, traceSvg(), h('b', null, title), text ? h('span', null, text) : null);
}