Chat: Highlight a message if the current user is mentioned

jocadbz
Joca 2025-08-29 14:48:38 -03:00
parent 3a82e2a0d1
commit e18d7ba193
Signed by: jocadbz
GPG Key ID: B1836DCE2F50BDF7
3 changed files with 98 additions and 13 deletions

View File

@ -127,6 +127,18 @@ func ChatHandler(app *App) http.HandlerFunc {
} }
} }
currentUser, err := models.GetUserByID(app.DB, userID)
if err != nil {
log.Printf("Error fetching current user: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
if currentUser == nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
currentUsername := currentUser.Username
if r.URL.Query().Get("ws") == "true" { if r.URL.Query().Get("ws") == "true" {
ws, err := upgrader.Upgrade(w, r, nil) ws, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
@ -203,6 +215,7 @@ func ChatHandler(app *App) http.HandlerFunc {
Board models.Board Board models.Board
Messages []models.ChatMessage Messages []models.ChatMessage
AllUsernames template.JS AllUsernames template.JS
CurrentUsername string
}{ }{
PageData: PageData{ PageData: PageData{
Title: "ThreadR Chat - " + board.Name, Title: "ThreadR Chat - " + board.Name,
@ -216,6 +229,7 @@ func ChatHandler(app *App) http.HandlerFunc {
Board: *board, Board: *board,
Messages: messages, Messages: messages,
AllUsernames: template.JS(allUsernamesJSON), AllUsernames: template.JS(allUsernamesJSON),
CurrentUsername: currentUsername,
} }
if err := app.Tmpl.ExecuteTemplate(w, "chat", data); err != nil { if err := app.Tmpl.ExecuteTemplate(w, "chat", data); err != nil {
log.Printf("Error executing template in ChatHandler: %v", err) log.Printf("Error executing template in ChatHandler: %v", err)

View File

@ -284,6 +284,23 @@ p.board-desc {
color: #fef6e4; color: #fef6e4;
} }
/* New style for highlighted chat messages */
.chat-message-highlighted {
border: 2px solid #f582ae; /* Pink border */
background-color: #ffe0f0; /* Light pink background */
animation: highlight-fade 2s ease-out;
}
@keyframes highlight-fade {
from {
background-color: #f582ae;
border-color: #f582ae;
}
to {
background-color: #ffe0f0;
border-color: #f582ae;
}
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body { body {
background-color: #333; background-color: #333;
@ -347,6 +364,22 @@ p.board-desc {
p, a, li { p, a, li {
color: #fef6e4; color: #fef6e4;
} }
/* Dark mode highlight */
.chat-message-highlighted {
border: 2px solid #f582ae; /* Pink border */
background-color: #6a0e3f; /* Darker pink background */
animation: highlight-fade-dark 2s ease-out;
}
@keyframes highlight-fade-dark {
from {
background-color: #f582ae;
border-color: #f582ae;
}
to {
background-color: #6a0e3f;
border-color: #f582ae;
}
}
} }
@media (max-width: 600px) { @media (max-width: 600px) {

View File

@ -172,6 +172,22 @@
background: none; background: none;
color: #f582ae; color: #f582ae;
} }
/* New style for highlighted messages */
.chat-message-highlighted {
border: 2px solid #f582ae; /* Pink border */
background-color: #ffe0f0; /* Light pink background */
animation: highlight-fade 2s ease-out;
}
@keyframes highlight-fade {
from {
background-color: #f582ae;
border-color: #f582ae;
}
to {
background-color: #ffe0f0;
border-color: #f582ae;
}
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
.chat-container { .chat-container {
background-color: #444; background-color: #444;
@ -217,6 +233,22 @@
.reply-indicator button:hover { .reply-indicator button:hover {
color: #f582ae; color: #f582ae;
} }
/* Dark mode highlight */
.chat-message-highlighted {
border: 2px solid #f582ae; /* Pink border */
background-color: #6a0e3f; /* Darker pink background */
animation: highlight-fade-dark 2s ease-out;
}
@keyframes highlight-fade-dark {
from {
background-color: #f582ae;
border-color: #f582ae;
}
to {
background-color: #6a0e3f;
border-color: #f582ae;
}
}
} }
</style> </style>
</head> </head>
@ -230,7 +262,7 @@
</header> </header>
<div class="chat-messages" id="chat-messages"> <div class="chat-messages" id="chat-messages">
{{range .Messages}} {{range .Messages}}
<div class="chat-message" id="msg-{{.ID}}"> <div class="chat-message{{if .Mentions}}{{range .Mentions}}{{if eq . $.CurrentUsername}} chat-message-highlighted{{end}}{{end}}{{end}}" id="msg-{{.ID}}">
<div class="chat-message-header"> <div class="chat-message-header">
{{if .PfpFileID.Valid}} {{if .PfpFileID.Valid}}
<img src="{{$.BasePath}}/file?id={{.PfpFileID.Int64}}" alt="PFP" class="chat-message-pfp"> <img src="{{$.BasePath}}/file?id={{.PfpFileID.Int64}}" alt="PFP" class="chat-message-pfp">
@ -267,6 +299,7 @@
let autocompleteActive = false; let autocompleteActive = false;
let replyToId = -1; let replyToId = -1;
const allUsernames = {{.AllUsernames}}; const allUsernames = {{.AllUsernames}};
const currentUsername = "{{.CurrentUsername}}"; // Get current user's username
function connectWebSocket() { function connectWebSocket() {
const boardID = {{.Board.ID}}; const boardID = {{.Board.ID}};
@ -305,7 +338,11 @@
function appendMessage(msg) { function appendMessage(msg) {
const messages = document.getElementById('chat-messages'); const messages = document.getElementById('chat-messages');
const msgDiv = document.createElement('div'); const msgDiv = document.createElement('div');
msgDiv.className = 'chat-message'; let highlightClass = '';
if (msg.mentions && msg.mentions.includes(currentUsername)) {
highlightClass = ' chat-message-highlighted';
}
msgDiv.className = 'chat-message' + highlightClass;
msgDiv.id = 'msg-' + msg.id; msgDiv.id = 'msg-' + msg.id;
let pfpHTML = `<div class="chat-message-pfp" style="background-color: #001858;"></div>`; let pfpHTML = `<div class="chat-message-pfp" style="background-color: #001858;"></div>`;
if (msg.pfpFileId && msg.pfpFileId.Valid) { if (msg.pfpFileId && msg.pfpFileId.Valid) {
@ -463,11 +500,12 @@
window.onload = function() { window.onload = function() {
connectWebSocket(); connectWebSocket();
document.querySelectorAll('.chat-message-content').forEach(function(el) { // This part is now handled by the server-side rendering with the `chat-message-highlighted` class
const text = el.innerHTML; // document.querySelectorAll('.chat-message-content').forEach(function(el) {
const newHTML = text.replace(/@(\w+)/g, '<span class="chat-message-mention">@$1</span>'); // const text = el.innerHTML;
el.innerHTML = newHTML; // const newHTML = text.replace(/@(\w+)/g, '<span class="chat-message-mention">@$1</span>');
}); // el.innerHTML = newHTML;
// });
document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight; document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight;
}; };