From ad71c41d89c88ac0f956c10279920265b6657179 Mon Sep 17 00:00:00 2001 From: Lucy Date: Mon, 3 Jun 2024 02:58:23 -0400 Subject: [PATCH 1/2] All-round TGChat improvements --- .../tgui-panel/chat/ChatPageSettings.js | 26 +- tgui/packages/tgui-panel/chat/actions.js | 1 + tgui/packages/tgui-panel/chat/middleware.js | 6 +- tgui/packages/tgui-panel/chat/model.js | 1 + tgui/packages/tgui-panel/chat/renderer.js | 51 +++- .../tgui-panel/chat/replaceInTextNode.js | 2 +- .../tgui-panel/settings/SettingsPanel.js | 224 +++++++++++------- tgui/packages/tgui-panel/settings/model.js | 1 + tgui/packages/tgui-panel/settings/reducer.js | 6 + .../tgui/styles/components/Button.scss | 7 +- 10 files changed, 213 insertions(+), 112 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/ChatPageSettings.js b/tgui/packages/tgui-panel/chat/ChatPageSettings.js index c0d9962d2531..8a8384835043 100644 --- a/tgui/packages/tgui-panel/chat/ChatPageSettings.js +++ b/tgui/packages/tgui-panel/chat/ChatPageSettings.js @@ -16,9 +16,9 @@ export const ChatPageSettings = (props, context) => { return (
- + dispatch( @@ -30,8 +30,25 @@ export const ChatPageSettings = (props, context) => { } /> + + + dispatch( + updateChatPage({ + pageId: page.id, + hideUnreadCount: !page.hideUnreadCount, + }) + ) + } + /> + + } + /> diff --git a/tgui/packages/tgui-panel/chat/actions.js b/tgui/packages/tgui-panel/chat/actions.js index e9919fcfa2b8..802801e63497 100644 --- a/tgui/packages/tgui-panel/chat/actions.js +++ b/tgui/packages/tgui-panel/chat/actions.js @@ -9,6 +9,7 @@ import { createPage } from './model'; export const loadChat = createAction('chat/load'); export const rebuildChat = createAction('chat/rebuild'); +export const clearChat = createAction('chat/clear'); export const updateMessageCount = createAction('chat/updateMessageCount'); export const addChatPage = createAction('chat/addPage', () => ({ payload: createPage(), diff --git a/tgui/packages/tgui-panel/chat/middleware.js b/tgui/packages/tgui-panel/chat/middleware.js index ecafbd23641f..05fb6041ce08 100644 --- a/tgui/packages/tgui-panel/chat/middleware.js +++ b/tgui/packages/tgui-panel/chat/middleware.js @@ -8,7 +8,7 @@ import DOMPurify from 'dompurify'; import { storage } from 'common/storage'; import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from '../settings/actions'; import { selectSettings } from '../settings/selectors'; -import { addChatPage, changeChatPage, changeScrollTracking, loadChat, rebuildChat, removeChatPage, saveChatToDisk, toggleAcceptedType, updateMessageCount } from './actions'; +import { addChatPage, changeChatPage, changeScrollTracking, clearChat, loadChat, rebuildChat, removeChatPage, saveChatToDisk, toggleAcceptedType, updateMessageCount } from './actions'; import { MAX_PERSISTED_MESSAGES, MESSAGE_SAVE_INTERVAL } from './constants'; import { createMessage, serializeMessage } from './model'; import { chatRenderer } from './renderer'; @@ -173,6 +173,10 @@ export const chatMiddleware = (store) => { chatRenderer.saveToDisk(); return; } + if (type === clearChat.type) { + chatRenderer.clearChat(); + return; + } return next(action); }; }; diff --git a/tgui/packages/tgui-panel/chat/model.js b/tgui/packages/tgui-panel/chat/model.js index fa12153890d8..99292e74fc01 100644 --- a/tgui/packages/tgui-panel/chat/model.js +++ b/tgui/packages/tgui-panel/chat/model.js @@ -22,6 +22,7 @@ export const createPage = (obj) => { name: 'New Tab', acceptedTypes: acceptedTypes, unreadCount: 0, + hideUnreadCount: false, createdAt: Date.now(), ...obj, }; diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.js index f7ce9277cf68..e8fb0970cf15 100644 --- a/tgui/packages/tgui-panel/chat/renderer.js +++ b/tgui/packages/tgui-panel/chat/renderer.js @@ -192,7 +192,8 @@ class ChatRenderer { const highlightWholeMessage = setting.highlightWholeMessage; const matchWord = setting.matchWord; const matchCase = setting.matchCase; - const allowedRegex = /^[a-z0-9_\-$/^[\s\]\\]+$/gi; + const enabled = setting.enabled; + const allowedRegex = /^[a-zа-яё0-9_\-$/^[\s\]\\]+$/gi; const lines = String(text) .split(',') .map((str) => str.trim()) @@ -247,6 +248,7 @@ class ChatRenderer { this.highlightParsers = []; } this.highlightParsers.push({ + enabled, highlightWords, highlightRegex, highlightColor, @@ -402,17 +404,19 @@ class ChatRenderer { // Highlight text if (!message.avoidHighlighting && this.highlightParsers) { - this.highlightParsers.map((parser) => { - const highlighted = highlightNode( - node, - parser.highlightRegex, - parser.highlightWords, - (text) => createHighlightNode(text, parser.highlightColor) - ); - if (highlighted && parser.highlightWholeMessage) { - node.className += ' ChatMessage--highlighted'; - } - }); + this.highlightParsers + .filter((parser) => parser.enabled) + .map((parser) => { + const highlighted = highlightNode( + node, + parser.highlightRegex, + parser.highlightWords, + (text) => createHighlightNode(text, parser.highlightColor) + ); + if (highlighted && parser.highlightWholeMessage) { + node.className += ' ChatMessage--highlighted'; + } + }); } // Linkify text const linkifyNodes = node.querySelectorAll('.linkify'); @@ -537,6 +541,29 @@ class ChatRenderer { }); } + /** + * @clearChat + * @copyright 2023 + * @author Cheffie + * @link https://github.com/CheffieGithub + * @license MIT + */ + clearChat() { + const messages = this.visibleMessages; + this.visibleMessages = []; + for (let i = 0; i < messages.length; i++) { + const message = messages[i]; + this.rootNode.removeChild(message.node); + // Mark this message as pruned + message.node = 'pruned'; + } + // Remove pruned messages from the message array + this.messages = this.messages.filter( + (message) => message.node !== 'pruned' + ); + logger.log(`Cleared chat`); + } + saveToDisk() { // Allow only on IE11 if (Byond.IS_LTE_IE10) { diff --git a/tgui/packages/tgui-panel/chat/replaceInTextNode.js b/tgui/packages/tgui-panel/chat/replaceInTextNode.js index 753997b3b821..8e616ea26cda 100644 --- a/tgui/packages/tgui-panel/chat/replaceInTextNode.js +++ b/tgui/packages/tgui-panel/chat/replaceInTextNode.js @@ -93,7 +93,7 @@ export const replaceInTextNode = (regex, words, createNode) => (node) => { for (let word of words) { // Capture if the word is at the beginning, end, middle, // or by itself in a message - wordRegexStr += `^${word}\\W|\\W${word}\\W|\\W${word}$|^${word}$`; + wordRegexStr += `^${word}\\s\\W|\\s\\W${word}\\s\\W|\\s\\W${word}$|^${word}\\s\\W$`; // Make sure the last character for the expression is NOT '|' if (++i !== words.length) { wordRegexStr += '|'; diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.js b/tgui/packages/tgui-panel/settings/SettingsPanel.js index 90abe4e36b26..c68fa0cd5012 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.js +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.js @@ -5,13 +5,14 @@ */ import { toFixed } from 'common/math'; +import { capitalize } from 'common/string'; import { useLocalState } from 'tgui/backend'; import { useDispatch, useSelector } from 'common/redux'; -import { Box, Button, ColorBox, Divider, Dropdown, Flex, Input, LabeledList, NumberInput, Section, Stack, Tabs, TextArea } from 'tgui/components'; +import { Box, Button, Collapsible, ColorBox, Divider, Stack, Input, LabeledList, NumberInput, Section, Tabs, TextArea } from 'tgui/components'; import { ChatPageSettings } from '../chat'; import { rebuildChat, saveChatToDisk } from '../chat/actions'; import { THEMES } from '../themes'; -import { changeSettingsTab, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions'; +import { clearChat, changeSettingsTab, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions'; import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants'; import { selectActiveTab, selectSettings, selectHighlightSettings, selectHighlightSettingById } from './selectors'; @@ -60,37 +61,61 @@ export const SettingsGeneral = (props, context) => {
- - dispatch( - updateSettings({ - theme: value, - }) - ) - } - /> + {THEMES.map((THEME) => ( + + + +
); }; @@ -163,30 +201,28 @@ const TextHighlightSettings = (props, context) => { const highlightSettings = useSelector(context, selectHighlightSettings); const dispatch = useDispatch(context); return ( -
-
- - {highlightSettings.map((id, i) => ( - + + {highlightSettings.map((id, i) => ( + + ))} + {highlightSettings.length < MAX_HIGHLIGHT_SETTINGS && ( + +
+ + )} +