From 00b8b1d024e727c3707daea60c82f9fa68ebec0f Mon Sep 17 00:00:00 2001 From: Rodrigo Emanuel Date: Mon, 2 Jun 2025 21:34:43 -0300 Subject: [PATCH] Horizontal Message Animation Adjust --- chat.html | 2 +- css/app.css | 13 +++++--- js/app.js | 78 +++++++++++++++++++++++++++++++++++++++++--- js/twitch/module.js | 11 ++----- js/youtube/module.js | 2 ++ 5 files changed, 89 insertions(+), 17 deletions(-) diff --git a/chat.html b/chat.html index 704d4a1..8c59a47 100644 --- a/chat.html +++ b/chat.html @@ -111,4 +111,4 @@ - + \ No newline at end of file diff --git a/css/app.css b/css/app.css index f8bf67b..f81cee9 100644 --- a/css/app.css +++ b/css/app.css @@ -467,20 +467,25 @@ body { - - .wrapper.horizontal { align-items: flex-end; } - .wrapper.horizontal #chat { flex-direction: row-reverse; align-items: flex-end; - gap: 10px; + gap: 15px; width: max-content; } +.wrapper.horizontal #chat .message { + width: 0; + white-space: nowrap +} + +.wrapper.horizontal #chat .message > div { + width: fit-content; +} diff --git a/js/app.js b/js/app.js index 0a926e1..623fb13 100644 --- a/js/app.js +++ b/js/app.js @@ -98,8 +98,8 @@ async function addMessageToChat(userID, messageID, platform, data) { if (ttsSpeakerBotChat == true) { ttsSpeakerBotSays(data.userName, currentLang.ttschat, data.message); } let html = DOMPurify.sanitize(` -
-
+
+
${data.classes.includes("first-message") ? '' : '' } @@ -142,9 +142,13 @@ async function addMessageToChat(userID, messageID, platform, data) { html = html.replace('[CHATMODERATIONSNIPPETYOUTUBE]', chatmodyoutube); chatContainer.insertAdjacentHTML('afterbegin', html); - + const messageElement = document.getElementById(messageID); + if (chatHorizontal == true) { + await adjustMessagesHorizontal(messageElement); + } + if (hideAfter > 0) { setTimeout(function () { messageElement.style.opacity = 0; @@ -159,13 +163,14 @@ async function addMessageToChat(userID, messageID, platform, data) { + async function addEventToChat(userID, messageID, platform, data) { if (ttsSpeakerBotEvents == true) { ttsSpeakerBotSays(data.userName, '', data.message); } const html = DOMPurify.sanitize(`
-
+
${!data.reply ? '' : data.reply} ${showPlatform == true ? '' : '' } @@ -182,6 +187,10 @@ async function addEventToChat(userID, messageID, platform, data) { const messageElement = document.getElementById(messageID); + if (chatHorizontal == true) { + await adjustMessagesHorizontal(messageElement); + } + if (hideAfter > 0) { setTimeout(function () { messageElement.style.opacity = 0; @@ -196,6 +205,67 @@ async function addEventToChat(userID, messageID, platform, data) { + + + + + + + + +async function adjustMessagesHorizontal(messageElement) { + const container = messageElement.querySelector('.animate__animated'); + if (!container) return; + + const images = container.querySelectorAll("img.emote"); + + function waitImageLoad(img) { + return new Promise((resolve) => { + if (img.complete) { + adjustEmotesWidthInMessage(img); + resolve(); + } + else { + img.addEventListener("load", () => { + adjustEmotesWidthInMessage(img); + resolve(); + }); + img.addEventListener("error", () => resolve()); + } + }); + } + + await Promise.all(Array.from(images).map(img => waitImageLoad(img))); + + const messageElementWidth = Math.floor(container.offsetWidth + 10) + 'px'; + + Object.assign(messageElement.style, { + width: messageElementWidth, + overflow: "visible" + }); +} + +function adjustEmotesWidthInMessage(img) { + const width = img.offsetWidth; + img.style.width = width + "px"; +} + + + + + + + + + + + + + + + + + const whatTimeIsIt = () => { const now = new Date(); const hours24 = now.getHours(); diff --git a/js/twitch/module.js b/js/twitch/module.js index bfa0c43..bcfdc42 100644 --- a/js/twitch/module.js +++ b/js/twitch/module.js @@ -601,16 +601,11 @@ async function getTwitchAvatar(user) { } else { console.debug(`Twitch avatar not found for ${user}! Getting it from DECAPI!`); - var decapi = await fetch('https://decapi.me/twitch/avatar/' + user); - var newavatar = await decapi.text(); - newavatar = newavatar.trim(); - - if (!newavatar || newavatar.startsWith("User not found:")) { - console.debug(`Avatar not found for ${user}. Using default image.`); - newavatar = 'https://static-cdn.jtvnw.net/user-default-pictures-uv/cdd517fe-def4-11e9-948e-784f43822e80-profile_image-300x300.png'; - } + var newavatar = await decapi.text() + if (!newavatar) { newavatar = 'https://static-cdn.jtvnw.net/user-default-pictures-uv/cdd517fe-def4-11e9-948e-784f43822e80-profile_image-300x300.png'; } + avatars.set(user, newavatar); return newavatar; } diff --git a/js/youtube/module.js b/js/youtube/module.js index f409d0b..0a916d3 100644 --- a/js/youtube/module.js +++ b/js/youtube/module.js @@ -302,6 +302,7 @@ async function YouTubeGiftReceivedMessage(data) { eventId: messageID, tier } = data; + const [avatar, message] = await Promise.all([ ``, currentLang.youtube.giftedmembers({ @@ -309,6 +310,7 @@ async function YouTubeGiftReceivedMessage(data) { tier : tier }) ]); + const classes = 'giftedtrainmembers'; const messageData = { classes: classes,