Public web-only release: SvxPortal front-end + auth backend, install templates and INSTALL.md
Stripped from the internal repo: per-box deploy trees, Go services (nodelist/astmeta/proxy/svxdr), deploy/sync scripts and all secrets. Config templates for nginx, PHP-FPM, Redis and tmpfiles live in install/ with CHANGEME placeholders. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
function updateTalkerPopup(nodes, talkerMeta){
|
||||
const popup = document.getElementById('talkerPopup');
|
||||
const title = document.getElementById('talkerTitle');
|
||||
const body = document.getElementById('talkerBody');
|
||||
|
||||
const calls = Object.keys(nodes || {});
|
||||
const talkers = calls
|
||||
.map(cs => ({ cs, n: nodes[cs] || {} }))
|
||||
.filter(x => x.n.isTalker === true && Number(x.n.tg || 0) !== 0);
|
||||
|
||||
if (talkers.length === 0) {
|
||||
popup.style.display = 'none';
|
||||
body.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
title.textContent = `Talking now: ${talkers.length}`;
|
||||
|
||||
const lines = talkers.map(t => {
|
||||
const tg = Number(t.n.tg || 0);
|
||||
const nodeType = t.n.nodeClass || 'node';
|
||||
const listeners = calls.filter(cs2 => includesTG(nodes[cs2], tg)).length;
|
||||
const sysop = (t.n.sysop && t.n.sysop !== t.cs) ? ` <span class="text-secondary">(${t.n.sysop})</span>` : '';
|
||||
// Bridge talker meta (via-gated): show the real talker behind the node
|
||||
const m = (talkerMeta || {})[String(tg)];
|
||||
const who = (m && m.callsign && (!m.via || m.via === t.cs))
|
||||
? `<b>${m.callsign}</b> <span class="text-secondary">via</span> <b>${t.cs}</b>`
|
||||
: `<b>${t.cs}</b>${sysop}`;
|
||||
return `<div>• ${who} <span class="text-secondary">(${nodeType})</span> — TG <b>${tg}</b> — listeners <b>${listeners}</b></div>`;
|
||||
});
|
||||
|
||||
body.innerHTML = lines.join('');
|
||||
popup.style.display = 'inline-flex';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user