[mirotalk] - Improve room emoji reactions with floating burst animation
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
# ====================================================
|
||||
# MiroTalk P2P v.1.8.23 - Environment Configuration
|
||||
# MiroTalk P2P v.1.8.24 - Environment Configuration
|
||||
# ====================================================
|
||||
|
||||
# App environment
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* ==============================================
|
||||
* MiroTalk P2P v.1.8.23 - Configuration File
|
||||
* MiroTalk P2P v.1.8.24 - Configuration File
|
||||
* ==============================================
|
||||
*
|
||||
* This file is the central configuration source.
|
||||
|
||||
+1
-1
@@ -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.23
|
||||
* @version 1.8.24
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mirotalk",
|
||||
"version": "1.8.23",
|
||||
"version": "1.8.24",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mirotalk",
|
||||
"version": "1.8.23",
|
||||
"version": "1.8.24",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@mattermost/client": "11.6.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalk",
|
||||
"version": "1.8.23",
|
||||
"version": "1.8.24",
|
||||
"description": "A free WebRTC browser-based video call",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
||||
+71
-4
@@ -2805,11 +2805,78 @@ button {
|
||||
}
|
||||
|
||||
.userEmoji {
|
||||
z-index: 18;
|
||||
z-index: 19;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.user-emoji-burst {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
bottom: 60px;
|
||||
border-radius: 10px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 14px;
|
||||
color: #fff;
|
||||
background: rgba(15, 23, 42, 0.34);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 22px 44px rgba(0, 0, 0, 0.22);
|
||||
backdrop-filter: blur(8px);
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(0, 0, 0) scale(0.82);
|
||||
animation: roomEmojiFloat 4.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
}
|
||||
|
||||
.user-emoji-burst__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: clamp(1.8rem, 1.2rem + 1.2vw, 2.7rem);
|
||||
line-height: 1;
|
||||
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.22));
|
||||
}
|
||||
|
||||
.user-emoji-burst__name {
|
||||
font-size: clamp(0.78rem, 0.68rem + 0.28vw, 0.95rem);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.01em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@keyframes roomEmojiFloat {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 28px, 0) scale(0.78) rotate(var(--emoji-rotation, 0deg));
|
||||
}
|
||||
12% {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0) scale(1) rotate(var(--emoji-rotation, 0deg));
|
||||
}
|
||||
78% {
|
||||
opacity: 1;
|
||||
transform: translate3d(var(--emoji-drift, 0px), calc(var(--emoji-rise, -180px) * 0.84), 0) scale(1.04)
|
||||
rotate(calc(var(--emoji-rotation, 0deg) * 0.4));
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate3d(calc(var(--emoji-drift, 0px) * 1.15), var(--emoji-rise, -180px), 0) scale(1.08)
|
||||
rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.user-emoji-burst {
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.user-emoji-burst__name {
|
||||
max-width: 32vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ let brand = {
|
||||
},
|
||||
about: {
|
||||
imageUrl: '../images/mirotalk-logo.gif',
|
||||
title: 'WebRTC P2P v1.8.23',
|
||||
title: 'WebRTC P2P v1.8.24',
|
||||
html: `
|
||||
<button
|
||||
id="support-button"
|
||||
|
||||
+75
-10
@@ -15,7 +15,7 @@
|
||||
* @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.23
|
||||
* @version 1.8.24
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -313,6 +313,13 @@ const CHAT_REACTION_EMOJIS = ['👍', '❤️', '😂', '😮', '😢', '🔥'];
|
||||
const CHAT_GPT_PEER_ID = 'chatgpt';
|
||||
const CHAT_GPT_NAME = 'ChatGPT';
|
||||
|
||||
const roomEmojiBurstState = {
|
||||
startedAt: 0,
|
||||
anchorX: 0,
|
||||
anchorY: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
// Chat room emoji picker
|
||||
const msgerEmojiPicker = getId('msgerEmojiPicker');
|
||||
|
||||
@@ -12926,6 +12933,55 @@ document.addEventListener('click', (event) => {
|
||||
msgerChat?.querySelectorAll('.reaction-picker').forEach((picker) => picker.remove());
|
||||
});
|
||||
|
||||
function getRoomEmojiPlacement() {
|
||||
const viewportWidth = Math.max(window.innerWidth || 0, 320);
|
||||
const viewportHeight = Math.max(window.innerHeight || 0, 320);
|
||||
const isCompactViewport = viewportWidth < 640;
|
||||
const now = Date.now();
|
||||
const burstWindow = 900;
|
||||
const maxBurstSize = isCompactViewport ? 4 : 6;
|
||||
const marginX = isCompactViewport ? 18 : 34;
|
||||
const marginY = isCompactViewport ? 96 : 124;
|
||||
const minAnchorX = viewportWidth * 0.2;
|
||||
const maxAnchorX = viewportWidth * 0.8;
|
||||
const minAnchorY = viewportHeight * 0.42;
|
||||
const maxAnchorY = viewportHeight * 0.76;
|
||||
|
||||
if (now - roomEmojiBurstState.startedAt > burstWindow || roomEmojiBurstState.count >= maxBurstSize) {
|
||||
roomEmojiBurstState.startedAt = now;
|
||||
roomEmojiBurstState.count = 0;
|
||||
roomEmojiBurstState.anchorX = minAnchorX + Math.random() * Math.max(1, maxAnchorX - minAnchorX);
|
||||
roomEmojiBurstState.anchorY = minAnchorY + Math.random() * Math.max(1, maxAnchorY - minAnchorY);
|
||||
}
|
||||
|
||||
const burstIndex = roomEmojiBurstState.count;
|
||||
roomEmojiBurstState.count += 1;
|
||||
|
||||
const baseAngle = -90 + (burstIndex - (maxBurstSize - 1) / 2) * (isCompactViewport ? 24 : 18);
|
||||
const jitterAngle = Math.random() * 12 - 6;
|
||||
const angle = ((baseAngle + jitterAngle) * Math.PI) / 180;
|
||||
const radius = (isCompactViewport ? 18 : 24) + burstIndex * (isCompactViewport ? 14 : 18) + Math.random() * 14;
|
||||
const left = Math.min(
|
||||
viewportWidth - marginX,
|
||||
Math.max(marginX, roomEmojiBurstState.anchorX + Math.cos(angle) * radius)
|
||||
);
|
||||
const top = Math.min(
|
||||
viewportHeight - marginY,
|
||||
Math.max(marginY, roomEmojiBurstState.anchorY + Math.sin(angle) * radius * 0.6)
|
||||
);
|
||||
const drift = `${(Math.cos(angle) * (radius * 0.95) + (Math.random() * 18 - 9)).toFixed(0)}px`;
|
||||
const rise = `-${(Math.abs(Math.sin(angle)) * 70 + Math.random() * 70 + (isCompactViewport ? 120 : 165)).toFixed(0)}px`;
|
||||
const rotation = `${(Math.random() * 16 - 8).toFixed(1)}deg`;
|
||||
|
||||
return {
|
||||
left,
|
||||
top,
|
||||
drift,
|
||||
rise,
|
||||
rotation,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle room emoji reaction
|
||||
* @param {object} message
|
||||
@@ -12934,14 +12990,23 @@ document.addEventListener('click', (event) => {
|
||||
function handleEmoji(message, duration = 5000) {
|
||||
if (userEmoji) {
|
||||
const emojiDisplay = document.createElement('div');
|
||||
emojiDisplay.className = 'animate__animated animate__backInUp';
|
||||
emojiDisplay.style.padding = '10px';
|
||||
emojiDisplay.style.fontSize = '2vh';
|
||||
emojiDisplay.style.color = '#FFF';
|
||||
emojiDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.2)';
|
||||
emojiDisplay.style.borderRadius = '10px';
|
||||
emojiDisplay.style.marginBottom = '5px';
|
||||
emojiDisplay.innerText = `${message.emoji} ${message.peer_name}`;
|
||||
const placement = getRoomEmojiPlacement();
|
||||
const label = message.peer_name || 'Guest';
|
||||
const emojiIcon = document.createElement('span');
|
||||
const emojiName = document.createElement('span');
|
||||
|
||||
emojiDisplay.className = 'user-emoji-burst';
|
||||
emojiDisplay.style.left = `${placement.left}px`;
|
||||
emojiDisplay.style.top = `${placement.top}px`;
|
||||
emojiDisplay.style.setProperty('--emoji-drift', placement.drift);
|
||||
emojiDisplay.style.setProperty('--emoji-rise', placement.rise);
|
||||
emojiDisplay.style.setProperty('--emoji-rotation', placement.rotation);
|
||||
emojiIcon.className = 'user-emoji-burst__icon';
|
||||
emojiIcon.textContent = message.emoji;
|
||||
emojiName.className = 'user-emoji-burst__name';
|
||||
emojiName.textContent = label;
|
||||
emojiDisplay.appendChild(emojiIcon);
|
||||
emojiDisplay.appendChild(emojiName);
|
||||
userEmoji.appendChild(emojiDisplay);
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -15580,7 +15645,7 @@ function showAbout() {
|
||||
Swal.fire({
|
||||
background: swBg,
|
||||
position: 'center',
|
||||
title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.8.23',
|
||||
title: brand.about?.title && brand.about.title.trim() !== '' ? brand.about.title : 'WebRTC P2P v1.8.24',
|
||||
imageUrl: brand.about?.imageUrl && brand.about.imageUrl.trim() !== '' ? brand.about.imageUrl : images.about,
|
||||
customClass: { image: 'img-about' },
|
||||
html: `
|
||||
|
||||
Reference in New Issue
Block a user