From e0174e450c704860d342bdd76603a6c78732e9f9 Mon Sep 17 00:00:00 2001 From: Lorenzune Date: Tue, 21 Apr 2026 08:54:02 +0200 Subject: [PATCH] Align wired chat limits and formatting help UI --- src/api/utils/RoomChatFormatter.ts | 44 +++++++++++++- .../WiredActionBotTalkToAvatarView.tsx | 13 ++++- .../views/actions/WiredActionBotTalkView.tsx | 13 ++++- .../views/actions/WiredActionChatView.tsx | 29 ++++++++-- .../views/common/WiredTextFormattingHelp.tsx | 58 +++++++++++++++++++ 5 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 src/components/wired/views/common/WiredTextFormattingHelp.tsx diff --git a/src/api/utils/RoomChatFormatter.ts b/src/api/utils/RoomChatFormatter.ts index 6ca8964..a47dd2f 100644 --- a/src/api/utils/RoomChatFormatter.ts +++ b/src/api/utils/RoomChatFormatter.ts @@ -40,11 +40,53 @@ const encodeHTML = (str: string) => }); }; +const formatTag = (content: string, tag: string, replacement: (value: string) => string) => +{ + const pattern = new RegExp(`\\[${ tag }\\]([\\s\\S]*?)\\[\\/${ tag }\\]`, 'gi'); + let previous = ''; + let next = content; + let guard = 0; + + while((previous !== next) && (guard < 20)) + { + previous = next; + next = next.replace(pattern, (match, value) => replacement(value)); + guard++; + } + + return next; +}; + +const applyWiredTextMarkup = (content: string) => +{ + const colorStyles: Record = { + green: '#008000', + cyan: '#008b8b', + red: '#d60000', + blue: '#005dff', + purple: '#7d31b8' + }; + + let result = content; + + result = formatTag(result, 'b', value => `${ value }`); + result = formatTag(result, 'i', value => `${ value }`); + result = formatTag(result, 'u', value => `${ value }`); + + Object.entries(colorStyles).forEach(([ tag, color ]) => + { + result = formatTag(result, tag, value => `${ value }`); + }); + + return result; +}; + export const RoomChatFormatter = (content: string) => { let result = ''; content = encodeHTML(content); + content = applyWiredTextMarkup(content); //content = (joypixels.shortnameToUnicode(content) as string) if(!GetConfigurationValue('youtube.publish.disabled', false)) @@ -84,5 +126,5 @@ export const RoomChatFormatter = (content: string) => result = content; } - return result; + return result.replace(/\r\n|\r|\n/g, '
'); }; diff --git a/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx b/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx index 5d7db10..9d91996 100644 --- a/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx +++ b/src/components/wired/views/actions/WiredActionBotTalkToAvatarView.tsx @@ -1,9 +1,10 @@ import { FC, useEffect, useState } from 'react'; -import { GetConfigurationValue, LocalizeText, WIRED_STRING_DELIMETER, WiredFurniType } from '../../../../api'; +import { LocalizeText, WIRED_STRING_DELIMETER, WiredFurniType } from '../../../../api'; import { Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { NitroInput } from '../../../../layout'; import { WiredActionBaseView } from './WiredActionBaseView'; +import { WiredTextCounter, WiredTextFormattingHelp } from '../common/WiredTextFormattingHelp'; import { BOT_SOURCES, WiredSourcesSelector } from '../WiredSourcesSelector'; const normalizeBotSource = (value: number, hasBotName = false) => (BOT_SOURCES.some(option => (option.value === value)) ? value : (hasBotName ? 100 : 0)); @@ -15,6 +16,7 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props => const [ talkMode, setTalkMode ] = useState(-1); const [ botSource, setBotSource ] = useState(100); const { trigger = null, setStringParam = null, setIntParams = null } = useWired(); + const maxMessageLength = 100; const [ userSource, setUserSource ] = useState(() => { if(trigger?.intData?.length > 1) return trigger.intData[1]; @@ -59,7 +61,14 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props => }
{ LocalizeText('wiredfurni.params.message') } - ('wired.action.bot.talk.to.avatar.max.length', 64) } type="text" value={ message } onChange={ event => setMessage(event.target.value) } /> +