From 3301dfbe4d80079443254e43d3ad3f549103472e Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 2 May 2026 23:03:33 +0200 Subject: [PATCH] [mirotalk] - refactor(chat): migrate room UI markup to templates and CSS, fix private/chatgpt entries, and keep sender info visible --- .env.template | 2 +- app/src/config.template.js | 2 +- app/src/server.js | 2 +- package-lock.json | 14 +- package.json | 4 +- public/css/client.css | 21 +- public/js/brand.js | 2 +- public/js/client.js | 371 +++++++++++++++++------------------- public/views/client.html | 226 ++++++++++++++++++++++ tests/test-RoomTemplates.js | 120 ++++++++++++ 10 files changed, 556 insertions(+), 208 deletions(-) create mode 100644 tests/test-RoomTemplates.js diff --git a/.env.template b/.env.template index 27b8eeb4..24ac3fdd 100644 --- a/.env.template +++ b/.env.template @@ -1,5 +1,5 @@ # ==================================================== -# MiroTalk P2P v.1.8.28 - Environment Configuration +# MiroTalk P2P v.1.8.30 - Environment Configuration # ==================================================== # App environment diff --git a/app/src/config.template.js b/app/src/config.template.js index 7dc863c5..5627bd38 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -2,7 +2,7 @@ /** * ============================================== - * MiroTalk P2P v.1.8.28 - Configuration File + * MiroTalk P2P v.1.8.30 - Configuration File * ============================================== * * This file is the central configuration source. diff --git a/app/src/server.js b/app/src/server.js index ea36ab06..e1cb298a 100755 --- a/app/src/server.js +++ b/app/src/server.js @@ -45,7 +45,7 @@ dependencies: { * @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.8.28 + * @version 1.8.30 * */ diff --git a/package-lock.json b/package-lock.json index c4addaf3..911c5efe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "mirotalk", - "version": "1.8.28", + "version": "1.8.30", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mirotalk", - "version": "1.8.28", + "version": "1.8.30", "license": "AGPL-3.0", "dependencies": { "@mattermost/client": "11.6.0", "@ngrok/ngrok": "1.7.0", "@sentry/node": "^10.51.0", - "axios": "^1.15.2", + "axios": "^1.16.0", "chokidar": "^5.0.0", "colors": "^1.4.0", "compression": "^1.8.1", @@ -1718,12 +1718,12 @@ } }, "node_modules/axios": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", - "integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz", + "integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } diff --git a/package.json b/package.json index ec16db6d..0a45c6f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalk", - "version": "1.8.28", + "version": "1.8.30", "description": "A free WebRTC browser-based video call", "main": "server.js", "scripts": { @@ -47,7 +47,7 @@ "@mattermost/client": "11.6.0", "@ngrok/ngrok": "1.7.0", "@sentry/node": "^10.51.0", - "axios": "^1.15.2", + "axios": "^1.16.0", "chokidar": "^5.0.0", "colors": "^1.4.0", "compression": "^1.8.1", diff --git a/public/css/client.css b/public/css/client.css index 182fa8e7..573eef3f 100755 --- a/public/css/client.css +++ b/public/css/client.css @@ -1996,15 +1996,15 @@ body { } .msg-grouped .msg-img { - visibility: hidden; + visibility: visible; } .msg-grouped .msg-info-name { - display: none; + display: inline; } .msg-grouped .msg-info { - justify-content: flex-end; + justify-content: space-between; } .msger-copy-txt { @@ -2902,6 +2902,16 @@ button { align-items: center; } +.share-room-modal-highlight { + color: rgb(8, 189, 89); +} + +.share-room-modal-description { + background: transparent; + color: #fff; + font-family: Arial, Helvetica, sans-serif; +} + #qrRoomPopupContainer { z-index: 9999; position: fixed; @@ -2930,6 +2940,11 @@ button { height: 256px; } +.kicked-out-modal-alert-title, +.kicked-out-modal-alert-time { + color: #ff2d00; +} + /*-------------------------------------------------------------- # My settings --------------------------------------------------------------*/ diff --git a/public/js/brand.js b/public/js/brand.js index 8ac6a475..7ca7de44 100644 --- a/public/js/brand.js +++ b/public/js/brand.js @@ -109,7 +109,7 @@ let brand = { }, about: { imageUrl: '../images/mirotalk-logo.gif', - title: 'WebRTC P2P v1.8.28', + title: 'WebRTC P2P v1.8.30', html: ` `; - msgHTML += ` + messageActionsHTML += ` `; if (isSpeechSynthesisSupported) { - msgHTML += ` + messageActionsHTML += ` `; } - msgHTML += ` - -
- - - - - `; + + const msgHTML = renderRoomTemplate('tpl-msger-chat-message', { + text: { + senderName: getFrom, + messageTime: time, + }, + html: { + messageActions: messageActionsHTML, + }, + attrs: { + messageContainerId: `msg-${chatMessagesId}`, + messageContainerClass: `msg ${getSide}-msg`, + chatType: getPrivateMsg ? 'private' : 'public', + chatPeer: conversationPeer, + messageId: normalizedMsgId, + messageAvatarTmpId: msgAvatarTmpId, + messageBubbleClass: msgBubble, + messageTextId: `message-${chatMessagesId}`, + }, + }); msgerChat.insertAdjacentHTML('beforeend', msgHTML); const msgAvatarEl = document.getElementById(msgAvatarTmpId); @@ -11069,8 +11079,9 @@ function resolvePeerNameById(peerId = '') { if (peerId === CHAT_GPT_PEER_ID) return CHAT_GPT_NAME; const privateChatButton = getId(peerId + '_pMsgBtn'); - if (privateChatButton?.value) { - return privateChatButton.value; + const privatePeerName = privateChatButton?.dataset?.value || privateChatButton?.getAttribute('data-value'); + if (privatePeerName) { + return privatePeerName; } return allPeers[peerId]?.peer_name || ''; @@ -11104,31 +11115,22 @@ function ensureChatGPTConversationEntry() { return; } - const chatGPTEntry = ` -
-
- ${CHAT_GPT_NAME} - - ${CHAT_GPT_NAME} - Ask anything - - -
-
- `; + const chatGPTEntry = renderRoomTemplate('tpl-chatgpt-participant-entry', { + text: { + participantName: CHAT_GPT_NAME, + participantSubtitle: 'Ask anything', + }, + attrs: { + participantName: CHAT_GPT_NAME, + entryId: `${CHAT_GPT_PEER_ID}_pMsgDiv`, + entryPeerName: CHAT_GPT_NAME.toLowerCase(), + buttonId: `${CHAT_GPT_PEER_ID}_pMsgBtn`, + participantPeerId: CHAT_GPT_PEER_ID, + avatarId: `${CHAT_GPT_PEER_ID}_pMsgAvatar`, + avatarSrc: images.chatgpt, + badgeId: `${CHAT_GPT_PEER_ID}_pMsgBadge`, + }, + }); msgerCPList.insertAdjacentHTML('afterbegin', chatGPTEntry); @@ -11471,28 +11473,33 @@ async function msgerAddPeers(peers) { `; } - const msgerPrivateDiv = ` -
-
- ${peer_name} - - ${peer_name} - Open private conversation - - - -
-
- `; + const msgerPrivateDiv = renderRoomTemplate('tpl-msger-private-entry', { + text: { + participantName: peer_name, + participantSubtitle: 'Open private conversation', + }, + html: { + dropdownOptions, + }, + attrs: { + participantName: peer_name, + entryId: `${peer_id}_pMsgDiv`, + entryPeerName: peer_name.toLowerCase(), + buttonId: `${peer_id}_pMsgBtn`, + participantPeerId: peer_id, + avatarTmpId: `${peer_id}_pMsgAvatar`, + badgeId: `${peer_id}_pMsgBadge`, + dropdownMenuId: `${peer_id}_pDropdownMenu`, + dropdownToggleId: `${peer_id}_pDropdownToggle`, + dropdownListId: `${peer_id}_pDropdownMenuList`, + }, + }); msgerCPList.insertAdjacentHTML('beforeend', msgerPrivateDiv); + const participantAvatar = getId(`${peer_id}_pMsgAvatar`); + if (participantAvatar) { + participantAvatar.setAttribute('src', chatAvatar); + } msgerCPList.scrollTop += 500; const msgerPrivateBtn = getId(peer_id + '_pMsgBtn'); @@ -11988,17 +11995,11 @@ function emitMsg(from, fromAvatar, to, msg, privateMsg, id, msgId = '') { function showAITypingIndicator(aiName) { const existing = getId(`ai-typing-${aiName}`); if (existing) return; - const typingHTML = ` -
-
-
- - - -
-
-
- `; + const typingHTML = renderRoomTemplate('tpl-ai-typing-indicator', { + attrs: { + typingIndicatorId: `ai-typing-${aiName}`, + }, + }); msgerChat.insertAdjacentHTML('beforeend', typingHTML); msgerChat.scrollTop = msgerChat.scrollHeight; } @@ -14053,25 +14054,7 @@ function createStickyNote() { Swal.fire({ background: swBg, title: 'Create Sticky Note', - html: ` -
- -
-
- - -
-
- - -
-
-
- `, + html: renderRoomTemplate('tpl-sticky-note-form'), showCancelButton: true, confirmButtonText: 'Create', cancelButtonText: 'Cancel', @@ -14198,25 +14181,13 @@ async function openFilePickerModal(config) { position: 'center', title: title, input: 'file', - html: ` -
- - -
- `, + html: renderRoomTemplate('tpl-file-picker-modal', { + text: { + emptyStateTitle, + emptyStateSubtitle, + helperText, + }, + }), inputAttributes: { accept: accept, 'aria-label': title, @@ -15742,11 +15713,11 @@ function handleKickedOut(config) { position: 'center', imageUrl: images.leave, title: 'Kicked out!', - html: - `

` + - `User ` + - peer_name + - `

will kick out you after milliseconds.`, + html: renderRoomTemplate('tpl-kicked-out-modal', { + text: { + peerName: peer_name, + }, + }), timer: 5000, timerProgressBar: true, didOpen: () => { @@ -15776,50 +15747,19 @@ function handleKickedOut(config) { function showAbout() { playSound('newMessage'); + const aboutHtml = brand.about.html; + Swal.fire({ background: swBg, position: 'center', - title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.8.28', + title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.8.30', imageUrl: brand.about?.imageUrl && brand.about.imageUrl.trim() !== '' ? brand.about.imageUrl : images.about, customClass: { image: 'img-about' }, - html: ` -
-
- ${ - brand.about?.html && brand.about.html.trim() !== '' - ? brand.about.html - : ` - -


- Author: - - Miroslav Pejic - -

- Email: - - miroslav.pejic.85@gmail.com - -

-
- © 2025 MiroTalk P2P, all rights reserved -
- ` - } -
- `, + html: renderRoomTemplate('tpl-about-modal', { + html: { + aboutHtml, + }, + }), showClass: { popup: 'animate__animated animate__fadeInDown' }, hideClass: { popup: 'animate__animated animate__fadeOutUp' }, }); @@ -16942,3 +16882,50 @@ function displayElements(elements) { function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } + +/** + * Render HTML template with provided data + * @param {string} templateId - ID of the