fix(ui): remove remaining JS template literals from dashboard; add link cards rendering
This commit is contained in:
parent
3f94aa7068
commit
a223663ce2
1 changed files with 7 additions and 14 deletions
|
|
@ -332,15 +332,7 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
|
||||||
if(!res.ok){ throw new Error('HTTP '+res.status); }
|
if(!res.ok){ throw new Error('HTTP '+res.status); }
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
async function loadInfo(){
|
async function loadInfo(){ /* no-op for now; footer shows version */ }
|
||||||
try{ const data = await api('/api/info');
|
|
||||||
document.getElementById('version').textContent = data.version+ ' ('+data.commit+')';
|
|
||||||
document.getElementById('built').textContent = data.builtAt;
|
|
||||||
document.getElementById('uptime').textContent = data.uptime;
|
|
||||||
document.getElementById('connected').textContent = data.connected? 'yes':'no';
|
|
||||||
document.getElementById('counts').textContent = 'ingested ' + data.messagesIngested + ', notified ' + data.notificationsSent + ', pruned ' + data.messagesPruned;
|
|
||||||
}catch(e){ console.error(e); }
|
|
||||||
}
|
|
||||||
async function loadChannels(){
|
async function loadChannels(){
|
||||||
try{ const data = await api('/api/channels'); st.channels = data; renderChannels(); if(data.length>0){ selectChannel(data[0]); } }
|
try{ const data = await api('/api/channels'); st.channels = data; renderChannels(); if(data.length>0){ selectChannel(data[0]); } }
|
||||||
catch(e){ console.error(e); }
|
catch(e){ console.error(e); }
|
||||||
|
|
@ -353,11 +345,12 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
|
||||||
catch(e){}
|
catch(e){}
|
||||||
} } }
|
} } }
|
||||||
function colorFor(nick){ let h=0; for(let i=0;i<nick.length;i++){ h=(h*31+nick.charCodeAt(i))>>>0 } return 'hsl('+(h%360)+',60%,'+(window.matchMedia('(prefers-color-scheme: dark)').matches? '70%':'35%')+')'; }
|
function colorFor(nick){ let h=0; for(let i=0;i<nick.length;i++){ h=(h*31+nick.charCodeAt(i))>>>0 } return 'hsl('+(h%360)+',60%,'+(window.matchMedia('(prefers-color-scheme: dark)').matches? '70%':'35%')+')'; }
|
||||||
function lineHTML(m){ const ts = `<span class=ts>[${m.time}]</span>`; const nick = `<b style="color:${colorFor(m.author)}">${m.author}</b>`; const body = escapeHtml(m.body); return `${ts} ${nick}: ${linkify(body)}`; }
|
function lineHTML(m){ const ts = '<span class=ts>[' + m.time + ']</span>'; const nick = '<b style="color:' + colorFor(m.author) + '\">' + m.author + '</b>'; const body = escapeHtml(m.body); return ts + ' ' + nick + ': ' + linkify(body); }
|
||||||
function escapeHtml(s){ return s.replace(/[&<>"]/g, c=>({'&':'&','<':'<','>':'>','"':'"'}[c])); }
|
function escapeHtml(s){ return s.replace(/[&<>"]/g, c=>({'&':'&','<':'<','>':'>','"':'"'}[c])); }
|
||||||
function linkify(t){ return t.replace(/https?:\/\/\S+/g, u=> `<a href="${u}" target="_blank" rel="noopener">${u}</a>`); }
|
function linkify(t){ return t.replace(/https?:\/\/\S+/g, function(u){ return '<a href="' + u + '" target="_blank" rel="noopener">' + u + '</a>'; }); }
|
||||||
function appendBatch(arr){ const el=document.getElementById('tail'); const frag=document.createDocumentFragment(); arr.forEach(m=>{ const div=document.createElement('div'); div.className='msg'; div.innerHTML=lineHTML(m); frag.appendChild(div); }); el.appendChild(frag); if(st.atBottom){ el.scrollTop = el.scrollHeight; } }
|
function appendBatch(arr){ const el=document.getElementById('tail'); const frag=document.createDocumentFragment(); arr.forEach(m=>{ const div=document.createElement('div'); div.className='msg'; div.innerHTML=lineHTML(m); frag.appendChild(div); processLinks(div); }); el.appendChild(frag); if(st.atBottom){ el.scrollTop = el.scrollHeight; } }
|
||||||
function prependBatch(arr){ const el=document.getElementById('tail'); const oldTop=el.firstChild; const frag=document.createDocumentFragment(); arr.forEach(m=>{ const div=document.createElement('div'); div.className='msg'; div.innerHTML=lineHTML(m); frag.appendChild(div); }); el.insertBefore(frag, el.firstChild); if(oldTop){ oldTop.scrollIntoView(); } }
|
function prependBatch(arr){ const el=document.getElementById('tail'); const oldTop=el.firstChild; const frag=document.createDocumentFragment(); arr.forEach(m=>{ const div=document.createElement('div'); div.className='msg'; div.innerHTML=lineHTML(m); frag.appendChild(div); processLinks(div); }); el.insertBefore(frag, el.firstChild); if(oldTop){ oldTop.scrollIntoView(); } }
|
||||||
|
function processLinks(scope){ const links = scope.querySelectorAll('a[href]:not([data-card])'); links.forEach(a=>{ a.setAttribute('data-card','1'); fetch('/api/linkcard?url='+encodeURIComponent(a.href)).then(r=>r.json()).then(card=>{ if(!card) return; if(card.title||card.description||card.image){ const c=document.createElement('div'); c.className='card'; var html=''; if(card.image){ html += '<div><img src="'+card.image+'" alt="" style="max-width:160px;max-height:120px;object-fit:cover;border-radius:.25rem"></div>'; } html += '<div style="flex:1;margin-left:.5rem">'; if(card.title){ html += '<div style="font-weight:600">'+escapeHtml(card.title)+'</div>'; } if(card.description){ html += '<div style="opacity:.8">'+escapeHtml(card.description)+'</div>'; } html += '</div>'; c.innerHTML = '<div style="display:flex;align-items:flex-start;gap:.5rem">'+html+'</div>'; a.parentNode.insertBefore(c, a.nextSibling); } }).catch(()=>{}); }); }
|
||||||
function startStream(){ const url=new URL('/api/stream', window.location.origin); url.searchParams.set('channel', st.current); const es=new EventSource(url); st.sse=es; es.onmessage=(ev)=>{ try{ const m=JSON.parse(ev.data); appendBatch([m]); }catch(e){} }; es.onerror=()=>{ es.close(); st.sse=null; setTimeout(startStream, 3000); } }
|
function startStream(){ const url=new URL('/api/stream', window.location.origin); url.searchParams.set('channel', st.current); const es=new EventSource(url); st.sse=es; es.onmessage=(ev)=>{ try{ const m=JSON.parse(ev.data); appendBatch([m]); }catch(e){} }; es.onerror=()=>{ es.close(); st.sse=null; setTimeout(startStream, 3000); } }
|
||||||
async function doSumm(){
|
async function doSumm(){
|
||||||
const ch = document.getElementById('channel').value;
|
const ch = document.getElementById('channel').value;
|
||||||
|
|
@ -373,7 +366,7 @@ func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
|
||||||
}catch(e){ document.getElementById('summary').textContent = 'error: '+e; }
|
}catch(e){ document.getElementById('summary').textContent = 'error: '+e; }
|
||||||
btn.disabled = false; prog.style.display = 'none';
|
btn.disabled = false; prog.style.display = 'none';
|
||||||
}
|
}
|
||||||
window.addEventListener('DOMContentLoaded', ()=>{ loadInfo(); loadChannels(); });
|
window.addEventListener('DOMContentLoaded', ()=>{ loadChannels(); });
|
||||||
function onFollowToggle(cb){
|
function onFollowToggle(cb){
|
||||||
if(cb.checked){
|
if(cb.checked){
|
||||||
if(st.tailTimer) clearInterval(st.tailTimer);
|
if(st.tailTimer) clearInterval(st.tailTimer);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue