This commit is contained in:
Evgeny @ SimpleX Chat
2026-05-31 11:16:15 +00:00
parent f41ba24311
commit c964bf35a5
+74 -37
View File
@@ -110,7 +110,7 @@ const STYLE = `
.simplex-preview-msg-name {
font-size: 13.5px;
color: #8b8786;
padding: 0 0 2px 45px;
padding: 0 0 2px 34px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -133,16 +133,15 @@ const STYLE = `
}
.simplex-preview-msg-avatar {
width: 37px;
height: 37px;
border-radius: 50%;
width: 30px;
height: 30px;
border-radius: 7px;
object-fit: cover;
flex-shrink: 0;
align-self: flex-end;
}
.simplex-preview-msg-avatar-placeholder {
width: 37px;
width: 30px;
flex-shrink: 0;
}
@@ -151,27 +150,46 @@ const STYLE = `
background: #f5f5f6;
border-radius: 18px;
min-width: 80px;
overflow: visible;
}
.simplex-preview-bubble-inner {
border-radius: 18px;
overflow: hidden;
}
.simplex-preview-bubble.has-tail {
margin-left: 9px;
}
.simplex-preview-bubble.has-tail .simplex-preview-bubble-inner {
border-bottom-left-radius: 4px;
}
.simplex-preview-bubble-tail {
position: absolute;
bottom: 0;
left: -7px;
width: 11px;
height: 17px;
overflow: hidden;
left: -9px;
width: 9px;
height: 16px;
}
.simplex-preview-bubble-tail svg {
.simplex-preview-bubble.media-only {
background: transparent;
}
.simplex-preview-meta-overlay {
position: absolute;
bottom: 0;
left: 0;
bottom: 6px;
right: 12px;
font-size: 12px;
color: #fff;
mix-blend-mode: difference;
white-space: nowrap;
}
.simplex-preview-meta-overlay .simplex-preview-meta-edited {
font-style: italic;
}
.simplex-preview-forwarded-header {
@@ -379,7 +397,11 @@ const STYLE = `
const DEFAULT_AVATAR = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25.8 25.46"><circle cx="12.9" cy="12.73" r="12.72" fill="#eee"/><path d="M25.44 12.73c0 7.01-5.71 12.73-12.73 12.73C5.71 25.46 0 19.75 0 12.73 0 5.73 5.71.02 12.71.02c7.01 0 12.73 5.71 12.73 12.72zM4.22 17.11c0 .58.31.87 1.05.87h4.88c-.14-.26-.19-.55-.19-.82 0-1.03.59-2.19 1.63-3.1-.79-.5-1.75-.79-2.74-.79-2.37 0-4.63 1.68-4.63 3.84zm6.6.05c0 .56.36.82 1.27.82h8.1c.93 0 1.26-.26 1.26-.82 0-1.62-2.02-3.87-5.28-3.87-3.29 0-5.34 2.25-5.34 3.87zM6.66 9.87c0 1.37 1.01 2.42 2.19 2.42 1.2 0 2.2-1.05 2.2-2.43 0-1.33-1.02-2.36-2.2-2.36-1.16 0-2.19 1.05-2.19 2.37zm6.98-.5c0 1.56 1.13 2.78 2.52 2.78 1.36 0 2.5-1.22 2.5-2.79 0-1.53-1.15-2.71-2.5-2.71-1.38 0-2.52 1.21-2.52 2.73z" fill="#ccc" fill-opacity=".85"/></svg>');
const TAIL_SVG = `<svg width="11" height="17" viewBox="0 0 11 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11 0 L11 17 L0 17 Q9 14.5 9 5.7 L9 0 Z" fill="#f5f5f6"/></svg>`;
const TAIL_SVG_COLOR = '#f5f5f6';
function tailSvg(color) {
return `<svg width="9" height="16" viewBox="0 0 9 16" xmlns="http://www.w3.org/2000/svg"><path d="M9 0 L9 16 L0 16 Q9 10.94 9 0 Z" fill="${color}"/></svg>`;
}
const FILE_ICON_SVG = `<svg class="simplex-preview-file-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14,2 14,8 20,8"/></svg>`;
@@ -574,51 +596,66 @@ function renderMessages(container, messages, membersMap, channel) {
}
function renderBubble(msg, member, showTail) {
const mc = msg.content;
const mediaOnly = (mc.type === 'image' || mc.type === 'video') && !mc.text && !msg.quote && !msg.forward;
const bubble = document.createElement('div');
bubble.className = 'simplex-preview-bubble' + (showTail ? ' has-tail' : '');
bubble.className = 'simplex-preview-bubble' + (showTail ? ' has-tail' : '') + (mediaOnly ? ' media-only' : '');
if (showTail) {
const tail = document.createElement('div');
tail.className = 'simplex-preview-bubble-tail';
tail.innerHTML = TAIL_SVG;
tail.innerHTML = tailSvg(mediaOnly ? 'transparent' : TAIL_SVG_COLOR);
bubble.appendChild(tail);
}
const inner = document.createElement('div');
inner.className = 'simplex-preview-bubble-inner';
if (msg.forward) {
const fwd = document.createElement('div');
fwd.className = 'simplex-preview-forwarded-header';
fwd.innerHTML = FORWARD_ICON_SVG + ' <span>Forwarded</span>';
bubble.appendChild(fwd);
inner.appendChild(fwd);
}
if (msg.quote) {
bubble.appendChild(renderQuote(msg.quote));
inner.appendChild(renderQuote(msg.quote));
}
const mc = msg.content;
switch (mc.type) {
case 'image':
renderImageContent(bubble, mc, msg);
renderImageContent(inner, mc, msg, mediaOnly);
break;
case 'video':
renderVideoContent(bubble, mc, msg);
renderVideoContent(inner, mc, msg, mediaOnly);
break;
case 'link':
renderLinkContent(bubble, mc, msg);
renderLinkContent(inner, mc, msg);
break;
case 'voice':
renderVoiceContent(bubble, mc, msg);
renderVoiceContent(inner, mc, msg);
break;
case 'file':
renderFileContent(bubble, mc, msg);
renderFileContent(inner, mc, msg);
break;
default:
renderTextContent(bubble, msg);
renderTextContent(inner, msg);
break;
}
if (msg.reactions && msg.reactions.length > 0) {
bubble.appendChild(renderReactions(msg.reactions));
inner.appendChild(renderReactions(msg.reactions));
}
bubble.appendChild(inner);
if (mediaOnly) {
const overlay = document.createElement('div');
overlay.className = 'simplex-preview-meta-overlay';
if (msg.edited) overlay.innerHTML = '<span class="simplex-preview-meta-edited">edited </span>';
overlay.innerHTML += formatTime(msg.ts);
bubble.appendChild(overlay);
}
return bubble;
@@ -667,22 +704,22 @@ function renderQuote(quote) {
return quoteDiv;
}
function renderImageContent(bubble, mc, msg) {
function renderImageContent(inner, mc, msg, mediaOnly) {
if (mc.image) {
const img = document.createElement('img');
img.className = 'simplex-preview-image';
img.src = mc.image;
img.alt = 'Image';
bubble.appendChild(img);
inner.appendChild(img);
}
if (mc.text) {
appendTextBlock(bubble, msg);
} else {
appendMetaOnly(bubble, msg);
appendTextBlock(inner, msg);
} else if (!mediaOnly) {
appendMetaOnly(inner, msg);
}
}
function renderVideoContent(bubble, mc, msg) {
function renderVideoContent(inner, mc, msg, mediaOnly) {
if (mc.image) {
const wrapper = document.createElement('div');
wrapper.style.position = 'relative';
@@ -695,12 +732,12 @@ function renderVideoContent(bubble, mc, msg) {
dur.style.cssText = 'position:absolute;bottom:4px;left:8px;background:rgba(0,0,0,0.6);color:#fff;font-size:12px;padding:1px 6px;border-radius:4px;';
dur.textContent = formatDuration(mc.duration || 0);
wrapper.appendChild(dur);
bubble.appendChild(wrapper);
inner.appendChild(wrapper);
}
if (mc.text) {
appendTextBlock(bubble, msg);
} else {
appendMetaOnly(bubble, msg);
appendTextBlock(inner, msg);
} else if (!mediaOnly) {
appendMetaOnly(inner, msg);
}
}