From dd3ddd9cc2e3e0246136ba22451dee2e35006c29 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Fri, 27 Mar 2026 05:07:55 +0100 Subject: [PATCH] fix(federation): fix badge positioning and tooltip text for file attachments - Use inline badges for file/audio attachments (next to file size) instead of absolute positioning which overflowed the container - Keep overlay badges for images/video (overflow-hidden containers) - Match tooltip text to toast notification text for consistency --- .../components/chat/AttachmentRenderer.tsx | 114 ++++++++++-------- 1 file changed, 62 insertions(+), 52 deletions(-) diff --git a/packages/web/src/components/chat/AttachmentRenderer.tsx b/packages/web/src/components/chat/AttachmentRenderer.tsx index 1361fcf5..6741741e 100644 --- a/packages/web/src/components/chat/AttachmentRenderer.tsx +++ b/packages/web/src/components/chat/AttachmentRenderer.tsx @@ -29,12 +29,11 @@ export function AttachmentRenderer({ attachment }: AttachmentRendererProps) { const { mimetype, originalName, size } = attachment; - // Federation status badge - const federationBadge = (() => { + // Federation status — build tooltip text + const federationTooltip = (() => { if (!attachment.federationStatus) return null; if (attachment.federationStatus === 'remote') { - // Receiving side — file hosted on sender's instance let senderName = 'the sender'; if (attachment.federationMeta) { try { @@ -42,48 +41,57 @@ export function AttachmentRenderer({ attachment }: AttachmentRendererProps) { if (meta.sourceUsername) senderName = meta.sourceUsername; } catch { /* ignore */ } } - return ( - -
- - - -
-
- ); + return { text: `Hosted on ${senderName}'s instance. Download to keep a local copy.`, type: 'remote' as const }; } if (attachment.federationStatus === 'remote_partial') { - // Sending side — file rejected by some peers - let tooltipText = 'Some recipients cannot cache this file locally.'; + let text = 'Some recipients cannot cache this file locally.'; if (attachment.federationMeta) { try { const meta: Array<{ username: string; limit: number }> = JSON.parse(attachment.federationMeta); if (meta.length > 0) { const parts = meta.map(u => { const limitMb = Math.round(u.limit / (1024 * 1024)); - return `${u.username}'s instance limit (${limitMb} MB)`; + return `${u.username}'s instance (limit: ${limitMb} MB)`; }); - tooltipText = `Exceeds ${parts.join(' and ')}. They can still view this file from your instance.`; + text = `File couldn't be cached on ${parts.join(' and ')}. They can still view it from yours.`; } } catch { /* ignore */ } } - return ( - -
- - - - - -
-
- ); + return { text, type: 'remote_partial' as const }; } return null; })(); + // Overlay badge for media (images/video) — absolute positioned inside overflow-hidden container + const federationOverlayBadge = federationTooltip ? ( + +
+ + {federationTooltip.type === 'remote' + ? + : <> + } + +
+
+ ) : null; + + // Inline badge for file cards (audio/generic) — sits inside the card layout, not absolute + const federationInlineBadge = federationTooltip ? ( + +
+ + {federationTooltip.type === 'remote' + ? + : <> + } + +
+
+ ) : null; + if (mimetype.startsWith('image/')) { const { width, height } = attachment; return ( @@ -98,7 +106,7 @@ export function AttachmentRenderer({ attachment }: AttachmentRendererProps) { onClick={() => openImagePreview(attUrl)} loading="lazy" /> - {federationBadge} + {federationOverlayBadge} ); } @@ -120,7 +128,7 @@ export function AttachmentRenderer({ attachment }: AttachmentRendererProps) { Your browser does not support video playback. - {federationBadge} + {federationOverlayBadge} ); } @@ -141,41 +149,43 @@ export function AttachmentRenderer({ attachment }: AttachmentRendererProps) {

{originalName}

-

{formatFileSize(size)}

+
+

{formatFileSize(size)}

+ {federationInlineBadge} +
- {federationBadge} ); } return ( -
- -
- - - -
-
-

{originalName}

+
+
+ + + +
+
+

{originalName}

+

{formatFileSize(size)}

+ {federationInlineBadge}
-
- {federationBadge} -
+
+ ); }