76 lines
2.6 KiB
JavaScript
76 lines
2.6 KiB
JavaScript
// Lotus Chat in-game voice overlay (cinny-desktop #25).
|
|||
|
|
//
|
||
|
|
// Rust (native/overlay.rs) calls window.lotusOverlay(state, maxRows) with the
|
||
|
|
// call snapshot from the web app. Everything is rendered with textContent /
|
||
|
|
// createElement, never markup strings, so a display name can't inject HTML.
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
(function () {
|
||
|
|
var panel = document.getElementById('panel');
|
||
|
|
var selfRow = document.getElementById('self');
|
||
|
|
var list = document.getElementById('people');
|
||
|
|
|
||
|
|
// Stable colour per user, from the user ID.
|
||
|
|
var COLOURS = ['#7c5cff', '#2f9e8f', '#d9822b', '#c2417c', '#3d7be0', '#5aa02c', '#a35bd6', '#c94f4f'];
|
||
|
|
function colourFor(id) {
|
||
|
|
var h = 0;
|
||
|
|
for (var i = 0; i < id.length; i += 1) h = (h * 31 + id.charCodeAt(i)) >>> 0;
|
||
|
|
return COLOURS[h % COLOURS.length];
|
||
|
|
}
|
||
|
|
|
||
|
|
function initial(name) {
|
||
|
|
var trimmed = (name || '').replace(/^[@#!+]/, '').trim();
|
||
|
|
var first = Array.from(trimmed)[0];
|
||
|
|
return first ? first.toUpperCase() : '?';
|
||
|
|
}
|
||
|
|
|
||
|
|
function el(tag, cls, text) {
|
||
|
|
var node = document.createElement(tag);
|
||
|
|
if (cls) node.className = cls;
|
||
|
|
if (text !== undefined) node.textContent = text;
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
function badge(text, off) {
|
||
|
|
return el('span', off ? 'badge off' : 'badge', text);
|
||
|
|
}
|
||
|
|
|
||
|
|
function renderSelf(state) {
|
||
|
|
selfRow.replaceChildren();
|
||
|
|
selfRow.appendChild(el('span', '', 'Lotus voice'));
|
||
|
|
if (state.deafened) selfRow.appendChild(badge('Deafened', true));
|
||
|
|
else if (state.muted) selfRow.appendChild(badge('Muted', true));
|
||
|
|
if (state.ptt) selfRow.appendChild(badge('PTT', false));
|
||
|
|
}
|
||
|
|
|
||
|
|
function renderPerson(p) {
|
||
|
|
var row = el('li', 'person');
|
||
|
|
if (p.speaking) row.classList.add('speaking');
|
||
|
|
if (p.muted) row.classList.add('muted');
|
||
|
|
var avatar = el('span', 'avatar', initial(p.name));
|
||
|
|
avatar.style.background = colourFor(p.userId || p.name || '');
|
||
|
|
row.appendChild(avatar);
|
||
|
|
row.appendChild(el('span', 'name', p.isSelf ? p.name + ' (you)' : p.name));
|
||
|
|
if (p.muted) row.appendChild(el('span', 'mic', 'Muted'));
|
||
|
|
return row;
|
||
|
|
}
|
||
|
|
|
||
|
|
window.lotusOverlay = function (state, maxRows) {
|
||
|
|
if (!state || !state.active) {
|
||
|
|
panel.hidden = true;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
renderSelf(state);
|
||
|
|
list.replaceChildren();
|
||
|
|
var people = Array.isArray(state.people) ? state.people : [];
|
||
|
|
var limit = typeof maxRows === 'number' ? maxRows : 10;
|
||
|
|
people.slice(0, limit).forEach(function (p) {
|
||
|
|
list.appendChild(renderPerson(p));
|
||
|
|
});
|
||
|
|
if (people.length > limit) {
|
||
|
|
list.appendChild(el('li', 'more', '+' + (people.length - limit) + ' more'));
|
||
|
|
}
|
||
|
|
panel.hidden = false;
|
||
|
|
};
|
||
|
|
})();
|