Ajout de fonctionnalités de mention dans la shoutbox pour les modérateurs Twitch. Implémentation de la gestion des mentions d'utilisateurs avec un système de mise en surbrillance pour les messages contenant des mentions. Mise à jour de l'interface utilisateur pour permettre aux modérateurs de mentionner facilement d'autres utilisateurs et d'améliorer l'interaction dans la shoutbox.

This commit is contained in:
2026-03-06 23:59:04 +01:00
parent 10dd78f630
commit 64c043feb5
2 changed files with 54 additions and 8 deletions
+26 -3
View File
@@ -85,6 +85,8 @@ function userColor(name) {
return colorMap[name]; return colorMap[name];
} }
var currentUser = '{{ current_user.username }}';
function esc(t) { var d = document.createElement('div'); d.textContent = t; return d.innerHTML; } function esc(t) { var d = document.createElement('div'); d.textContent = t; return d.innerHTML; }
function fmtTime(iso) { function fmtTime(iso) {
@@ -92,6 +94,22 @@ function fmtTime(iso) {
return d.getHours().toString().padStart(2,'0') + ':' + d.getMinutes().toString().padStart(2,'0'); return d.getHours().toString().padStart(2,'0') + ':' + d.getMinutes().toString().padStart(2,'0');
} }
function mentionUser(username) {
var input = document.getElementById('shoutboxInput');
var val = input.value;
var mention = '@' + username + ' ';
if (val && !val.endsWith(' ')) mention = ' ' + mention;
input.value = val + mention;
input.focus();
}
function renderText(text) {
var escaped = esc(text);
var mentioned = currentUser && text.toLowerCase().indexOf('@' + currentUser.toLowerCase()) >= 0;
escaped = escaped.replace(/@(\w+)/g, '<span class="text-indigo-400 font-semibold">@$1</span>');
return { html: escaped, mentioned: mentioned };
}
function addItem(item) { function addItem(item) {
if (knownIds.has(item.id)) return; if (knownIds.has(item.id)) return;
knownIds.add(item.id); knownIds.add(item.id);
@@ -100,12 +118,16 @@ function addItem(item) {
if (ph) ph.remove(); if (ph) ph.remove();
var line = document.createElement('div'); var line = document.createElement('div');
line.className = 'py-0.5 leading-relaxed'; line.className = 'py-0.5 leading-relaxed rounded px-1';
var time = '<span class="text-gray-500">[' + fmtTime(item.created_at) + ']</span> '; var time = '<span class="text-gray-500">[' + fmtTime(item.created_at) + ']</span> ';
if (item.type === 'message') { if (item.type === 'message') {
var c = userColor(item.author); var c = userColor(item.author);
line.innerHTML = time + '<span style="color:' + c + '" class="font-semibold">&lt;' + esc(item.author) + '&gt;</span> <span class="text-gray-200">' + esc(item.text) + '</span>'; var rendered = renderText(item.text);
line.innerHTML = time + '<span style="color:' + c + '" class="font-semibold cursor-pointer hover:underline" onclick="mentionUser(\'' + esc(item.author).replace(/'/g, "\\'") + '\')">&lt;' + esc(item.author) + '&gt;</span> <span class="text-gray-200">' + rendered.html + '</span>';
if (rendered.mentioned) {
line.className += ' bg-red-900/40 font-bold';
}
} else { } else {
var au = (item.action || '').toUpperCase(); var au = (item.action || '').toUpperCase();
var sc = 'text-red-400'; var sc = 'text-red-400';
@@ -135,7 +157,8 @@ function updateOnline(users) {
list.innerHTML = ''; list.innerHTML = '';
users.forEach(function(u) { users.forEach(function(u) {
var el = document.createElement('div'); var el = document.createElement('div');
el.className = 'flex items-center gap-1.5 text-xs text-gray-300'; el.className = 'flex items-center gap-1.5 text-xs text-gray-300 cursor-pointer hover:text-white';
el.onclick = function() { mentionUser(u); };
el.innerHTML = '<span class="w-1.5 h-1.5 rounded-full bg-green-500 flex-shrink-0"></span>' + esc(u); el.innerHTML = '<span class="w-1.5 h-1.5 rounded-full bg-green-500 flex-shrink-0"></span>' + esc(u);
list.appendChild(el); list.appendChild(el);
}); });
+28 -5
View File
@@ -979,6 +979,7 @@ document.addEventListener('keydown', function(e) {
// ============================= // =============================
// Shoutbox modérateurs (IRC) // Shoutbox modérateurs (IRC)
// ============================= // =============================
var shoutboxCurrentUser = '{{ current_user.username }}';
var shoutboxKnownIds = new Set(); var shoutboxKnownIds = new Set();
var shoutboxLastTimestamp = ''; var shoutboxLastTimestamp = '';
var shoutboxAutoScroll = true; var shoutboxAutoScroll = true;
@@ -1025,6 +1026,23 @@ function shoutboxTime(isoStr) {
return d.getHours().toString().padStart(2, '0') + ':' + d.getMinutes().toString().padStart(2, '0'); return d.getHours().toString().padStart(2, '0') + ':' + d.getMinutes().toString().padStart(2, '0');
} }
function shoutboxMention(username) {
var input = document.getElementById('shoutboxInput');
var val = input.value;
var mention = '@' + username + ' ';
if (val && !val.endsWith(' ')) mention = ' ' + mention;
input.value = val + mention;
input.focus();
}
function shoutboxRenderText(text) {
var escaped = escapeHtml(text);
var isMentioned = shoutboxCurrentUser && text.toLowerCase().indexOf('@' + shoutboxCurrentUser.toLowerCase()) >= 0;
escaped = escaped.replace(/@(\w+)/g, '<span class="text-indigo-400 font-semibold">@$1</span>');
if (isMentioned) return { html: escaped, mentioned: true };
return { html: escaped, mentioned: false };
}
function addShoutboxItem(item) { function addShoutboxItem(item) {
if (shoutboxKnownIds.has(item.id)) return; if (shoutboxKnownIds.has(item.id)) return;
shoutboxKnownIds.add(item.id); shoutboxKnownIds.add(item.id);
@@ -1034,15 +1052,19 @@ function addShoutboxItem(item) {
if (ph) ph.remove(); if (ph) ph.remove();
var line = document.createElement('div'); var line = document.createElement('div');
line.className = 'py-0.5 leading-relaxed'; line.className = 'py-0.5 leading-relaxed rounded px-1';
var time = '<span class="text-gray-500">[' + shoutboxTime(item.created_at) + ']</span> '; var time = '<span class="text-gray-500">[' + shoutboxTime(item.created_at) + ']</span> ';
if (item.type === 'message') { if (item.type === 'message') {
var color = shoutboxColor(item.author); var color = shoutboxColor(item.author);
var rendered = shoutboxRenderText(item.text);
line.innerHTML = time + line.innerHTML = time +
'<span style="color:' + color + '" class="font-semibold">&lt;' + escapeHtml(item.author) + '&gt;</span> ' + '<span style="color:' + color + '" class="font-semibold cursor-pointer hover:underline" onclick="shoutboxMention(\'' + escapeHtml(item.author).replace(/'/g, "\\'") + '\')">&lt;' + escapeHtml(item.author) + '&gt;</span> ' +
'<span class="text-gray-200">' + escapeHtml(item.text) + '</span>'; '<span class="text-gray-200">' + rendered.html + '</span>';
if (rendered.mentioned) {
line.className += ' bg-red-900/40 font-bold';
}
} else { } else {
var actionUpper = (item.action || '').toUpperCase(); var actionUpper = (item.action || '').toUpperCase();
var sanctionColor = 'text-red-400'; var sanctionColor = 'text-red-400';
@@ -1052,7 +1074,7 @@ function addShoutboxItem(item) {
var text = '*** ' + actionUpper; var text = '*** ' + actionUpper;
if (item.moderator) text += ' par ' + item.moderator; if (item.moderator) text += ' par ' + item.moderator;
if (item.target) text += ' ' + item.target; if (item.target) text += ' \u2192 ' + item.target;
if (item.details && item.details !== '-') text += ' (' + item.details + ')'; if (item.details && item.details !== '-') text += ' (' + item.details + ')';
text += ' ***'; text += ' ***';
@@ -1077,7 +1099,8 @@ function updateOnlineList(users) {
list.innerHTML = ''; list.innerHTML = '';
users.forEach(function(u) { users.forEach(function(u) {
var el = document.createElement('div'); var el = document.createElement('div');
el.className = 'flex items-center gap-1.5 text-xs text-gray-300'; el.className = 'flex items-center gap-1.5 text-xs text-gray-300 cursor-pointer hover:text-white';
el.onclick = function() { shoutboxMention(u); };
el.innerHTML = '<span class="w-1.5 h-1.5 rounded-full bg-green-500 flex-shrink-0"></span>' + escapeHtml(u); el.innerHTML = '<span class="w-1.5 h-1.5 rounded-full bg-green-500 flex-shrink-0"></span>' + escapeHtml(u);
list.appendChild(el); list.appendChild(el);
}); });