From 21820fc4012355db7109a2d27bb84e6efa8559e2 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Sun, 10 Nov 2024 15:03:51 -0800 Subject: [PATCH 01/14] Convert icon in event messages into a button Also, display a vertical ellipsis when hovering over the button to indicate the clicking on it will bring up dropdown menu. --- assets/chat/css/messages/event/_event.scss | 16 ++++++++++++++-- assets/chat/img/icon-ellipsis-vertical.svg | 15 +++++++++++++++ assets/views/templates.html | 4 +++- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 assets/chat/img/icon-ellipsis-vertical.svg diff --git a/assets/chat/css/messages/event/_event.scss b/assets/chat/css/messages/event/_event.scss index a80ead6d..0412e9d5 100644 --- a/assets/chat/css/messages/event/_event.scss +++ b/assets/chat/css/messages/event/_event.scss @@ -32,8 +32,6 @@ } .event-icon { - width: 2.25em; - height: 2.25em; color: a.$color-chat-disabled; position: relative; text-decoration: none; @@ -41,6 +39,9 @@ border: 0.25em solid transparent; flex-shrink: 0; opacity: 0.75; + width: 100%; + height: 100%; + transition: background 200ms ease; } .event-bottom { @@ -50,6 +51,17 @@ border-bottom-left-radius: 10px; } + .event-button { + width: 2.25em; + height: 2.25em; + + &:hover { + .event-icon { + @include a.icon-background('../img/icon-ellipsis-vertical.svg'); + } + } + } + &:not(:has(.event-bottom)) { .event-top { border-bottom-right-radius: 10px; diff --git a/assets/chat/img/icon-ellipsis-vertical.svg b/assets/chat/img/icon-ellipsis-vertical.svg new file mode 100644 index 00000000..1de61600 --- /dev/null +++ b/assets/chat/img/icon-ellipsis-vertical.svg @@ -0,0 +1,15 @@ + + + + + diff --git a/assets/views/templates.html b/assets/views/templates.html index 79d86e5c..fa5cae10 100644 --- a/assets/views/templates.html +++ b/assets/views/templates.html @@ -3,7 +3,9 @@
- +
From 16c06115f5bdd2e56d2e85cdf52bad279a974ec7 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Sun, 10 Nov 2024 15:48:53 -0800 Subject: [PATCH 02/14] Display dropdown menu when event button is clicked --- assets/chat/css/menus/_event-action-menu.scss | 23 +++++++++++++++++++ assets/chat/css/menus/_index.scss | 1 + assets/chat/js/chat.js | 9 ++++++++ assets/chat/js/menus/ChatEventActionMenu.js | 17 ++++++++++++++ assets/chat/js/menus/index.js | 1 + assets/views/embed.html | 6 +++++ 6 files changed, 57 insertions(+) create mode 100644 assets/chat/css/menus/_event-action-menu.scss create mode 100644 assets/chat/js/menus/ChatEventActionMenu.js diff --git a/assets/chat/css/menus/_event-action-menu.scss b/assets/chat/css/menus/_event-action-menu.scss new file mode 100644 index 00000000..b9190f6e --- /dev/null +++ b/assets/chat/css/menus/_event-action-menu.scss @@ -0,0 +1,23 @@ +@use '../abstracts/' as a; + +#event-action-menu { + height: fit-content; + width: fit-content; + min-width: 75px; + max-width: 250px; + z-index: 221; + + .chat-menu-inner { + background-color: a.$color-surface-dark3; + } + + .event-action { + transition: background-color 150ms ease; + color: a.$color-light; + padding: 0.5rem 1rem; + + &:hover { + background-color: a.$color-surface-dark4; + } + } +} diff --git a/assets/chat/css/menus/_index.scss b/assets/chat/css/menus/_index.scss index 30135d81..6d9af991 100644 --- a/assets/chat/css/menus/_index.scss +++ b/assets/chat/css/menus/_index.scss @@ -7,6 +7,7 @@ @use 'user-info'; @use 'user-list'; @use 'whispers-list'; +@use 'event-action-menu'; .chat-menu { display: none; diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index fe71483b..be25a67c 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -31,6 +31,7 @@ import { ChatEmoteTooltip, ChatSettingsMenu, ChatUserInfoMenu, + ChatEventActionMenu, } from './menus'; import ChatEventBar from './event-bar/EventBar'; import ChatAutoComplete from './autocomplete'; @@ -377,6 +378,14 @@ class Chat { this, ), ); + this.menus.set( + 'event-action-menu', + new ChatEventActionMenu( + this.ui.find('#event-action-menu'), + this.ui.find('.msg-event .event-button'), + this, + ), + ); this.autocomplete.bind(this); diff --git a/assets/chat/js/menus/ChatEventActionMenu.js b/assets/chat/js/menus/ChatEventActionMenu.js new file mode 100644 index 00000000..bc3f0e16 --- /dev/null +++ b/assets/chat/js/menus/ChatEventActionMenu.js @@ -0,0 +1,17 @@ +import ChatMenuFloating from './ChatMenuFloating'; + +export default class ChatEventActionMenu extends ChatMenuFloating { + constructor(ui, btn, chat) { + super(ui, btn, chat); + + this.chat.ui.on('click', '.msg-event .event-button', (e) => { + this.openMenu(e); + return false; + }); + } + + openMenu(e) { + this.position(e); + this.show(); + } +} diff --git a/assets/chat/js/menus/index.js b/assets/chat/js/menus/index.js index 27fe072a..90ccead1 100644 --- a/assets/chat/js/menus/index.js +++ b/assets/chat/js/menus/index.js @@ -5,3 +5,4 @@ export { default as ChatEmoteMenu } from './ChatEmoteMenu'; export { default as ChatEmoteTooltip } from './ChatEmoteTooltip'; export { default as ChatWhisperUsers } from './ChatWhisperUsers'; export { default as ChatUserInfoMenu } from './ChatUserInfoMenu'; +export { default as ChatEventActionMenu } from './ChatEventActionMenu'; diff --git a/assets/views/embed.html b/assets/views/embed.html index 2fe68d05..330c56a8 100644 --- a/assets/views/embed.html +++ b/assets/views/embed.html @@ -371,4 +371,10 @@

Want to chat?

+ +
+
+ +
+
From 4a69c323f7bc4391ed56898aa602fa7836655872 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Sun, 10 Nov 2024 21:31:09 -0800 Subject: [PATCH 03/14] Only display action menu for removable events --- assets/chat/css/messages/event/_event.scss | 6 +++++- assets/chat/js/messages/ChatBroadcastMessage.js | 4 ++++ assets/chat/js/messages/ChatEventMessage.js | 9 +++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/assets/chat/css/messages/event/_event.scss b/assets/chat/css/messages/event/_event.scss index 0412e9d5..28956bb1 100644 --- a/assets/chat/css/messages/event/_event.scss +++ b/assets/chat/css/messages/event/_event.scss @@ -55,11 +55,15 @@ width: 2.25em; height: 2.25em; - &:hover { + &:hover:not(:disabled) { .event-icon { @include a.icon-background('../img/icon-ellipsis-vertical.svg'); } } + + &:disabled { + cursor: default; + } } &:not(:has(.event-bottom)) { diff --git a/assets/chat/js/messages/ChatBroadcastMessage.js b/assets/chat/js/messages/ChatBroadcastMessage.js index 67a24d9e..a1c1ced8 100644 --- a/assets/chat/js/messages/ChatBroadcastMessage.js +++ b/assets/chat/js/messages/ChatBroadcastMessage.js @@ -61,4 +61,8 @@ export default class ChatBroadcastMessage extends ChatEventMessage { return this.wrap(eventTemplate.innerHTML, classes, attributes); } + + get hasActions() { + return false; + } } diff --git a/assets/chat/js/messages/ChatEventMessage.js b/assets/chat/js/messages/ChatEventMessage.js index c41f9f31..3f3df7c0 100644 --- a/assets/chat/js/messages/ChatEventMessage.js +++ b/assets/chat/js/messages/ChatEventMessage.js @@ -30,10 +30,19 @@ export default class ChatEventMessage extends ChatMessage { eventTemplate.querySelector('.event-bottom').remove(); } + if (!this.hasActions) { + const eventButton = eventTemplate.querySelector('.event-button'); + eventButton.disabled = true; + } + return eventTemplate; } updateTimeFormat() { // This avoids errors. Timestamps aren't rendered in event messages. } + + get hasActions() { + return true; + } } From 0d11a56637c83c917132da810cadfcf4120e6693 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Mon, 11 Nov 2024 00:05:39 -0800 Subject: [PATCH 04/14] Dispatch `REMOVEEVENT` message when button clicked --- assets/chat/js/chat.js | 19 ++++++++++++------- assets/chat/js/menus/ChatEventActionMenu.js | 7 +++++++ assets/chat/js/messages/ChatEventMessage.js | 2 ++ assets/views/embed.html | 4 +++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index be25a67c..29584cc6 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -378,14 +378,14 @@ class Chat { this, ), ); - this.menus.set( - 'event-action-menu', - new ChatEventActionMenu( - this.ui.find('#event-action-menu'), - this.ui.find('.msg-event .event-button'), - this, - ), + + const eventActionMenu = new ChatEventActionMenu( + this.ui.find('#event-action-menu'), + this.ui.find('.msg-event .event-button'), + this, ); + eventActionMenu.on('removeEvent', this.handleRemoveEvent.bind(this)); + this.menus.set('event-action-menu', eventActionMenu); this.autocomplete.bind(this); @@ -2610,6 +2610,11 @@ class Chat { hostname = hostname.split('?')[0]; return hostname; } + + handleRemoveEvent(eventUuid) { + ChatMenu.closeMenus(this); + this.source.send('REMOVEEVENT', { data: eventUuid }); + } } export default Chat; diff --git a/assets/chat/js/menus/ChatEventActionMenu.js b/assets/chat/js/menus/ChatEventActionMenu.js index bc3f0e16..7c1c6c14 100644 --- a/assets/chat/js/menus/ChatEventActionMenu.js +++ b/assets/chat/js/menus/ChatEventActionMenu.js @@ -8,10 +8,17 @@ export default class ChatEventActionMenu extends ChatMenuFloating { this.openMenu(e); return false; }); + + this.ui.on('click', '#remove-event-button', this.removeEvent.bind(this)); } openMenu(e) { + this.eventElement = e.currentTarget.closest('.msg-event'); this.position(e); this.show(); } + + removeEvent() { + this.emit('removeEvent', this.eventElement.dataset.uuid); + } } diff --git a/assets/chat/js/messages/ChatEventMessage.js b/assets/chat/js/messages/ChatEventMessage.js index 3f3df7c0..fed04b93 100644 --- a/assets/chat/js/messages/ChatEventMessage.js +++ b/assets/chat/js/messages/ChatEventMessage.js @@ -35,6 +35,8 @@ export default class ChatEventMessage extends ChatMessage { eventButton.disabled = true; } + eventTemplate.dataset.uuid = this.uuid; + return eventTemplate; } diff --git a/assets/views/embed.html b/assets/views/embed.html index 330c56a8..fe60684d 100644 --- a/assets/views/embed.html +++ b/assets/views/embed.html @@ -374,7 +374,9 @@

Want to chat?

- +
From 139a9f08fb5868b4689c224dd62bd6a9a69ca761 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Mon, 11 Nov 2024 14:50:41 -0800 Subject: [PATCH 05/14] Fix issue where action menu dismisses event When an event is selected, user focus is enabled to darken the chat output underneath the event. However, because of how menus work, clicking on the button to open the event's action menu immediately dismisses the event. Reworking the markup and styles such that the selected event's container provides its own background fixes the issue. Now, clicking the container's background is the only way to dismiss the event. --- assets/chat/css/chat/_output.scss | 1 + assets/chat/css/chat/event-bar/_index.scss | 14 +++++++++----- assets/chat/js/chat.js | 1 - assets/chat/js/event-bar/EventBar.js | 11 +++++++++++ assets/chat/js/focus.js | 1 - assets/views/embed.html | 6 ++---- assets/views/stream.html | 6 ++---- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/assets/chat/css/chat/_output.scss b/assets/chat/css/chat/_output.scss index 89998b70..7e2bcef2 100644 --- a/assets/chat/css/chat/_output.scss +++ b/assets/chat/css/chat/_output.scss @@ -4,6 +4,7 @@ flex: 1; overflow: hidden; width: 100%; + position: relative; } .chat-output { diff --git a/assets/chat/css/chat/event-bar/_index.scss b/assets/chat/css/chat/event-bar/_index.scss index 4a6951a8..6a29d7f8 100644 --- a/assets/chat/css/chat/event-bar/_index.scss +++ b/assets/chat/css/chat/event-bar/_index.scss @@ -18,13 +18,12 @@ } } -#highlighted-message-wrapper { +#chat-event-selected { position: absolute; - width: 100%; z-index: 210; -} + inset: 0; + background-color: rgba(0, 0, 0, 0.5); -#chat-event-selected { .event-bar-selected-message { margin: a.$gutter-sm; @@ -32,6 +31,10 @@ opacity: 1; } } + + &.hidden { + display: none; + } } .onstreamchat { @@ -39,7 +42,8 @@ display: none; } - #highlighted-message-wrapper { + #chat-event-selected, + #chat-pinned-message { display: none; } } diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index 29584cc6..006d3042 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -1574,7 +1574,6 @@ class Chat { } onEVENTSELECTED() { - this.userfocus.toggleFocus('', false, true); // Hide full pinned message interface to make everything look nice if (this.pinnedMessage) this.pinnedMessage.hidden = true; } diff --git a/assets/chat/js/event-bar/EventBar.js b/assets/chat/js/event-bar/EventBar.js index 94221350..6ca1bb07 100644 --- a/assets/chat/js/event-bar/EventBar.js +++ b/assets/chat/js/event-bar/EventBar.js @@ -20,6 +20,15 @@ export default class ChatEventBar extends EventEmitter { }); } }); + + this.eventSelectUI.addEventListener('click', (e) => { + // Don't unselect if the selected event message is clicked + if (e.target !== e.currentTarget) { + return; + } + + this.unselect(); + }); } /** @@ -49,6 +58,7 @@ export default class ChatEventBar extends EventEmitter { unselect() { if (this.eventSelectUI.hasChildNodes()) { this.eventSelectUI.replaceChildren(); + this.eventSelectUI.classList.add('hidden'); this.emit('eventUnselected'); } } @@ -63,6 +73,7 @@ export default class ChatEventBar extends EventEmitter { this.eventSelectUI.replaceChildren(); this.eventSelectUI.append(event); + this.eventSelectUI.classList.remove('hidden'); this.emit('eventSelected'); } diff --git a/assets/chat/js/focus.js b/assets/chat/js/focus.js index 3e4d6bbd..7ff52857 100644 --- a/assets/chat/js/focus.js +++ b/assets/chat/js/focus.js @@ -11,7 +11,6 @@ class ChatUserFocus { this.focused = []; this.chat.output.on('click', (e) => { this.toggleElement(e.target); - this.chat.eventBar.unselect(); }); } diff --git a/assets/views/embed.html b/assets/views/embed.html index fe60684d..7725a32b 100644 --- a/assets/views/embed.html +++ b/assets/views/embed.html @@ -26,10 +26,8 @@
-
-
-
-
+ +
diff --git a/assets/views/stream.html b/assets/views/stream.html index 9800e006..37e9b2b6 100644 --- a/assets/views/stream.html +++ b/assets/views/stream.html @@ -2,9 +2,7 @@
-
-
-
-
+
+
From 351cfd99b3cb0d6c2f213ecc6bf4f5fe235777ca Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Mon, 11 Nov 2024 15:16:55 -0800 Subject: [PATCH 06/14] Fix issue where dismissing event cancels focus --- assets/chat/js/event-bar/EventBar.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assets/chat/js/event-bar/EventBar.js b/assets/chat/js/event-bar/EventBar.js index 6ca1bb07..ab238fb6 100644 --- a/assets/chat/js/event-bar/EventBar.js +++ b/assets/chat/js/event-bar/EventBar.js @@ -27,6 +27,9 @@ export default class ChatEventBar extends EventEmitter { return; } + // Prevent the click from canceling focus, if enabled + e.stopPropagation(); + this.unselect(); }); } From 848ac2a3f54878f313b2608bc72a519796664555 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Mon, 11 Nov 2024 15:56:30 -0800 Subject: [PATCH 07/14] Unselect an event when removed --- assets/chat/js/chat.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index 006d3042..9cd4e15b 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -385,6 +385,10 @@ class Chat { this, ); eventActionMenu.on('removeEvent', this.handleRemoveEvent.bind(this)); + eventActionMenu.on( + 'removeEvent', + this.eventBar.unselect.bind(this.eventBar), + ); this.menus.set('event-action-menu', eventActionMenu); this.autocomplete.bind(this); From 7f3dd0e51d1e7921c963376844ed43c0a9904354 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Mon, 11 Nov 2024 16:05:29 -0800 Subject: [PATCH 08/14] Only allow mods to open event action menu --- assets/chat/js/messages/ChatEventMessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/chat/js/messages/ChatEventMessage.js b/assets/chat/js/messages/ChatEventMessage.js index fed04b93..7e666a9c 100644 --- a/assets/chat/js/messages/ChatEventMessage.js +++ b/assets/chat/js/messages/ChatEventMessage.js @@ -30,7 +30,7 @@ export default class ChatEventMessage extends ChatMessage { eventTemplate.querySelector('.event-bottom').remove(); } - if (!this.hasActions) { + if (!this.hasActions || !chat.user?.hasModPowers()) { const eventButton = eventTemplate.querySelector('.event-button'); eventButton.disabled = true; } From 01fa06b7f0141525e6d9f2bc59ae08486b51ddd8 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Tue, 12 Nov 2024 18:06:23 -0800 Subject: [PATCH 09/14] Hold references to events in event bar This setup is necessary to allow the event bar to clear an event's progress bar update interval. Clearing the interval is necessary when the event is removed prior to its expiration. --- assets/chat/js/event-bar/EventBar.js | 10 +++++++++ assets/chat/js/event-bar/EventBarEvent.js | 25 ++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/assets/chat/js/event-bar/EventBar.js b/assets/chat/js/event-bar/EventBar.js index ab238fb6..c9ebe16f 100644 --- a/assets/chat/js/event-bar/EventBar.js +++ b/assets/chat/js/event-bar/EventBar.js @@ -5,6 +5,8 @@ import EventEmitter from '../emitter'; */ export default class ChatEventBar extends EventEmitter { + events = []; + constructor() { super(); /** @type HTMLDivElement */ @@ -43,9 +45,12 @@ export default class ChatEventBar extends EventEmitter { return; } + this.events.push(event); + event.element.addEventListener('click', () => { this.select(event.selectedElement); }); + event.on('eventExpired', this.removeEvent.bind(this)); this.eventBarUI.prepend(event.element); @@ -130,6 +135,11 @@ export default class ChatEventBar extends EventEmitter { return true; } + removeEvent(event) { + this.events = this.events.filter((e) => e.uuid !== event.uuid); + event.remove(); + } + get length() { return this.eventBarUI.querySelectorAll(`.event-bar-event`).length; } diff --git a/assets/chat/js/event-bar/EventBarEvent.js b/assets/chat/js/event-bar/EventBarEvent.js index a8e84655..119b008f 100644 --- a/assets/chat/js/event-bar/EventBarEvent.js +++ b/assets/chat/js/event-bar/EventBarEvent.js @@ -3,14 +3,17 @@ import { selectDonationTier } from '../messages/ChatDonationMessage'; import { getTierStyles } from '../messages/subscriptions/ChatSubscriptionMessage'; import { MessageBuilder, MessageTypes } from '../messages'; import ChatUser from '../user'; +import EventEmitter from '../emitter'; -export default class EventBarEvent { +export default class EventBarEvent extends EventEmitter { /** * @param {*} chat * @param {string} type * @param {import('./EventBar').ExpiringEvent} data */ constructor(chat, type, data) { + super(); + this.type = type; this.data = data; @@ -76,7 +79,7 @@ export default class EventBarEvent { const percentageLeft = this.calculateExpiryPercentage(); if (percentageLeft <= 0) { - this.remove(); + this.expire(); return; } @@ -133,11 +136,27 @@ export default class EventBarEvent { /** * @private */ + expire() { + this.stopUpdatingExpirationProgressBar(); + this.emit('eventExpired', this); + } + remove() { + this.stopUpdatingExpirationProgressBar(); + this.element.addEventListener('animationend', () => { this.element.remove(); - if (this.intervalID) clearInterval(this.intervalID); }); this.element.classList.add('removed'); } + + stopUpdatingExpirationProgressBar() { + if (this.intervalID) { + clearInterval(this.intervalID); + } + } + + get uuid() { + return this.data.uuid; + } } From 729b33728300522d44665e4e01ce5e972cf991d0 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Tue, 12 Nov 2024 18:32:13 -0800 Subject: [PATCH 10/14] Fix no effect when receiving updated `PAIDEVENTS` Removing an event broadcasts a new `PAIDEVENTS` message without the removed event. The previous implementation did not clear the event bar, first, which made it seem like the removal had no effect. --- assets/chat/js/chat.js | 9 +++++---- assets/chat/js/event-bar/EventBar.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index 9cd4e15b..294f64dc 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -1389,11 +1389,12 @@ class Chat { } onPAIDEVENTS(lines) { - lines.forEach((line) => { - const { eventname, data } = this.source.parse({ data: line }); - const eventBarEvent = new EventBarEvent(this, eventname, data); - this.eventBar.add(eventBarEvent); + const events = lines.map((l) => { + const { eventname, data } = this.source.parse({ data: l }); + return new EventBarEvent(this, eventname, data); }); + this.eventBar.replaceEvents(events); + this.mainwindow.update(); this.eventBar.sort(); } diff --git a/assets/chat/js/event-bar/EventBar.js b/assets/chat/js/event-bar/EventBar.js index c9ebe16f..de6f83eb 100644 --- a/assets/chat/js/event-bar/EventBar.js +++ b/assets/chat/js/event-bar/EventBar.js @@ -140,6 +140,22 @@ export default class ChatEventBar extends EventEmitter { event.remove(); } + removeAllEvents() { + for (const e of this.events) { + e.remove(); + } + + this.events = []; + } + + replaceEvents(events) { + this.removeAllEvents(); + + for (const e of events) { + this.add(e); + } + } + get length() { return this.eventBarUI.querySelectorAll(`.event-bar-event`).length; } From e90386de3f74299994ecc8d47a80e11024e69555 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Tue, 12 Nov 2024 18:36:52 -0800 Subject: [PATCH 11/14] Add error message whe event removal fails --- assets/chat/js/const.js | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/chat/js/const.js b/assets/chat/js/const.js index 7b518a4e..138a8004 100644 --- a/assets/chat/js/const.js +++ b/assets/chat/js/const.js @@ -106,6 +106,7 @@ const hintstrings = new Map( bigscreen: `Bigscreen! Did you know you can have the chat on the left or right side of the stream by clicking the swap icon in the top left?`, danisold: 'Destiny is an Amazon Associate. He earns a commission on qualifying purchases of any product on Amazon linked in Destiny.gg chat.', + cantremoveevent: 'This event could not be removed.', }), ); From 5988826c5a45694c9406ef325032213f24575534 Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Wed, 13 Nov 2024 11:34:32 -0800 Subject: [PATCH 12/14] Fix issue with events disappearing/reappearing `contains()` doesn't consider an event removed if it's still in the DOM. It isn't removed from the DOM until its remove animation is complete. When coupled with `add()` checking if an event already exists before adding it to the DOM, this can result in `replaceEvents()` simply removing all events from the event bar. Reworking `contains()` to use the `events` array to determine if an event already exists instead fixes the issue. This also disables animations when replacing events, which can look odd when the new `PAIDEVENTS` payload contains old events. --- .../chat/css/chat/event-bar/_event-bar-event.scss | 5 ++++- assets/chat/js/event-bar/EventBar.js | 15 +++++++++------ assets/chat/js/event-bar/EventBarEvent.js | 15 +++++++++++---- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/assets/chat/css/chat/event-bar/_event-bar-event.scss b/assets/chat/css/chat/event-bar/_event-bar-event.scss index a672258d..e91babda 100644 --- a/assets/chat/css/chat/event-bar/_event-bar-event.scss +++ b/assets/chat/css/chat/event-bar/_event-bar-event.scss @@ -5,7 +5,6 @@ position: relative; cursor: pointer; transition: transform 100ms; - animation: event-bar-appear 500ms linear; font-size: 1.1em; border-radius: 10px; @@ -106,6 +105,10 @@ &.removed { animation: event-bar-disappear 500ms linear; } + + &.enter { + animation: event-bar-appear 500ms linear; + } } @keyframes event-bar-appear { diff --git a/assets/chat/js/event-bar/EventBar.js b/assets/chat/js/event-bar/EventBar.js index de6f83eb..3755c12a 100644 --- a/assets/chat/js/event-bar/EventBar.js +++ b/assets/chat/js/event-bar/EventBar.js @@ -39,8 +39,9 @@ export default class ChatEventBar extends EventEmitter { /** * Adds the event to the event bar. * @param {EventBarEvent} event + * @param {boolean} animate Animate the addition of the event */ - add(event) { + add(event, animate = true) { if (!this.shouldEventBeDisplayed(event.data)) { return; } @@ -52,6 +53,10 @@ export default class ChatEventBar extends EventEmitter { }); event.on('eventExpired', this.removeEvent.bind(this)); + if (animate) { + event.element.classList.add('enter'); + } + this.eventBarUI.prepend(event.element); // // Update chat window to fix the scroll position @@ -92,9 +97,7 @@ export default class ChatEventBar extends EventEmitter { * @returns {boolean} */ contains(uuid) { - return !!this.eventBarUI.querySelector( - `.event-bar-event[data-uuid="${uuid}"]`, - ); + return this.events.some((e) => e.uuid === uuid); } /** @@ -142,7 +145,7 @@ export default class ChatEventBar extends EventEmitter { removeAllEvents() { for (const e of this.events) { - e.remove(); + e.remove(false); } this.events = []; @@ -152,7 +155,7 @@ export default class ChatEventBar extends EventEmitter { this.removeAllEvents(); for (const e of events) { - this.add(e); + this.add(e, false); } } diff --git a/assets/chat/js/event-bar/EventBarEvent.js b/assets/chat/js/event-bar/EventBarEvent.js index 119b008f..fdf14a84 100644 --- a/assets/chat/js/event-bar/EventBarEvent.js +++ b/assets/chat/js/event-bar/EventBarEvent.js @@ -141,13 +141,20 @@ export default class EventBarEvent extends EventEmitter { this.emit('eventExpired', this); } - remove() { + /** + * @param {boolean} animate Animate the removal of the event + */ + remove(animate = true) { this.stopUpdatingExpirationProgressBar(); - this.element.addEventListener('animationend', () => { + if (animate) { + this.element.addEventListener('animationend', () => { + this.element.remove(); + }); + this.element.classList.add('removed'); + } else { this.element.remove(); - }); - this.element.classList.add('removed'); + } } stopUpdatingExpirationProgressBar() { From bf7b3a5181d32be96aaf2fe67a464ce7727bebab Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Wed, 13 Nov 2024 12:26:27 -0800 Subject: [PATCH 13/14] No longer add events when loading from history The `PAIDEVENTS` payload will contain all the events in history. --- assets/chat/js/chat.js | 62 ++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index 294f64dc..37956368 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -1350,41 +1350,63 @@ class Chat { onSUBSCRIPTION(data) { MessageBuilder.subscription(data).into(this); - const eventBarEvent = new EventBarEvent( - this, - MessageTypes.SUBSCRIPTION, - data, - ); - this.eventBar.add(eventBarEvent); - if (this.eventBar.length === 1) { - this.mainwindow.update(); + + // Don't add events when loading messages from history because the + // `PAIDEVENTS` payload will contain those events + if (!this.backlogloading) { + const eventBarEvent = new EventBarEvent( + this, + MessageTypes.SUBSCRIPTION, + data, + ); + this.eventBar.add(eventBarEvent); + if (this.eventBar.length === 1) { + this.mainwindow.update(); + } } } onGIFTSUB(data) { MessageBuilder.gift(data).into(this); - const eventBarEvent = new EventBarEvent(this, MessageTypes.GIFTSUB, data); - this.eventBar.add(eventBarEvent); - if (this.eventBar.length === 1) { - this.mainwindow.update(); + + if (!this.backlogloading) { + const eventBarEvent = new EventBarEvent(this, MessageTypes.GIFTSUB, data); + this.eventBar.add(eventBarEvent); + if (this.eventBar.length === 1) { + this.mainwindow.update(); + } } } onMASSGIFT(data) { MessageBuilder.massgift(data).into(this); - const eventBarEvent = new EventBarEvent(this, MessageTypes.MASSGIFT, data); - this.eventBar.add(eventBarEvent); - if (this.eventBar.length === 1) { - this.mainwindow.update(); + + if (!this.backlogloading) { + const eventBarEvent = new EventBarEvent( + this, + MessageTypes.MASSGIFT, + data, + ); + this.eventBar.add(eventBarEvent); + if (this.eventBar.length === 1) { + this.mainwindow.update(); + } } } onDONATION(data) { MessageBuilder.donation(data).into(this); - const eventBarEvent = new EventBarEvent(this, MessageTypes.DONATION, data); - this.eventBar.add(eventBarEvent); - if (this.eventBar.length === 1) { - this.mainwindow.update(); + + if (!this.backlogloading) { + const eventBarEvent = new EventBarEvent( + this, + MessageTypes.DONATION, + data, + ); + this.eventBar.add(eventBarEvent); + if (this.eventBar.length === 1) { + this.mainwindow.update(); + } } } From f477329d7457eaa7d4983c883ae139f178118c4a Mon Sep 17 00:00:00 2001 From: Farhad Jay Date: Wed, 13 Nov 2024 13:54:13 -0800 Subject: [PATCH 14/14] Fix issue with expired events not being removed The event enter animation had a higher specificity than the remove animation, which meant the remove animation never took effect. Simply flipping the order of the two rulesets fixes the issue. --- assets/chat/css/chat/event-bar/_event-bar-event.scss | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/assets/chat/css/chat/event-bar/_event-bar-event.scss b/assets/chat/css/chat/event-bar/_event-bar-event.scss index e91babda..37bb53f2 100644 --- a/assets/chat/css/chat/event-bar/_event-bar-event.scss +++ b/assets/chat/css/chat/event-bar/_event-bar-event.scss @@ -102,13 +102,15 @@ transform: scale(1.05); } - &.removed { - animation: event-bar-disappear 500ms linear; - } - + // Ensure `removed` can override `enter` because `enter` is not removed from + // the event after the animation completes. &.enter { animation: event-bar-appear 500ms linear; } + + &.removed { + animation: event-bar-disappear 500ms linear; + } } @keyframes event-bar-appear {