import React from 'react'; import type { Attachment } from '@backspace/shared'; import { useUIStore } from '../../stores/uiStore'; import { Tooltip } from '../ui/Tooltip'; interface AttachmentRendererProps { attachment: Attachment; } function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / 1048576).toFixed(1)} MB`; } export function AttachmentRenderer({ attachment }: AttachmentRendererProps) { const openImagePreview = useUIStore((s) => s.openImagePreview); const attUrl = attachment.filename.startsWith('http') || attachment.filename.startsWith('/') ? attachment.filename : `/api/uploads/${attachment.filename}`; const thumbUrl = attachment.thumbnailFilename ? attachment.thumbnailFilename.startsWith('http') || attachment.thumbnailFilename.startsWith('/') ? attachment.thumbnailFilename : `/api/uploads/${attachment.thumbnailFilename}` : null; const { mimetype, originalName, size } = attachment; // Federation status — build tooltip text const federationTooltip = (() => { if (!attachment.federationStatus) return null; if (attachment.federationStatus === 'remote') { let senderName = 'the sender'; if (attachment.federationMeta) { try { const meta = JSON.parse(attachment.federationMeta); if (meta.sourceUsername) senderName = meta.sourceUsername; } catch { /* ignore */ } } return { text: `Hosted on ${senderName}'s instance. Download to keep a local copy.`, type: 'remote' as const }; } if (attachment.federationStatus === 'remote_partial') { 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)`; }); text = `File couldn't be cached on ${parts.join(' and ')}. They can still view it from yours.`; } } catch { /* ignore */ } } return { text, type: 'remote_partial' as const }; } return null; })(); // Inline badge — sits next to file size or below media, never absolute-positioned const federationInlineBadge = federationTooltip ? (
{federationTooltip.type === 'remote' ? : <> }
) : null; if (mimetype.startsWith('image/')) { const { width, height } = attachment; return (
{originalName} openImagePreview(attUrl)} loading="lazy" />
{federationInlineBadge &&
{federationInlineBadge}
}
); } if (mimetype.startsWith('video/')) { const { width, height } = attachment; const hasDimensions = width && height; return (
{federationInlineBadge &&
{federationInlineBadge}
}
); } if (mimetype.startsWith('audio/')) { return (

{originalName}

{formatFileSize(size)}

{federationInlineBadge}
); } return (

{originalName}

{formatFileSize(size)}

{federationInlineBadge}
); }