From c088b4c0e6eba6399916dc77bf3e577f30d451d7 Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Thu, 24 Sep 2026 21:51:33 -0400 Subject: [PATCH] feat(media): show the full caption under the media in the viewer (#164) A captioned image/video (MSC2530: `filename` set and `body` differs) put the caption in the header, truncated to one line, so a long caption was unreadable. The header now shows the file name; the caption is shown in full under the media (wrapped, scrolls past 25vh). The image alt text uses the caption, and Download now saves under the real file name instead of the caption. Verified in Chromium: header "lake-sunset.png", the 150-character caption fully visible below the image. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA --- src/app/features/room/MediaGallery.tsx | 43 ++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/app/features/room/MediaGallery.tsx b/src/app/features/room/MediaGallery.tsx index fd5350518..c11eea64e 100644 --- a/src/app/features/room/MediaGallery.tsx +++ b/src/app/features/room/MediaGallery.tsx @@ -106,6 +106,10 @@ export type LightboxItem = { mimeType?: string; msgtype: MsgType.Image | MsgType.Video; body: string; + /** The file's name when the message also carries a caption (MSC2530). */ + filename?: string; + /** Caption text: `body` when it differs from `filename`. */ + caption?: string; sender: string; ts: number; eventId: string; @@ -127,12 +131,19 @@ export function toLightboxItems(room: Room, events: MatrixEvent[]): LightboxItem .map((ev) => { const c = ev.getContent(); const isEnc = !!c.file; + const filename = typeof c.filename === 'string' && c.filename ? c.filename : undefined; + const caption = + filename && typeof c.body === 'string' && c.body && c.body !== filename + ? c.body + : undefined; return { mxcUrl: c.file?.url ?? c.url ?? '', encInfo: isEnc ? c.file : undefined, mimeType: c.info?.mimetype, msgtype: c.msgtype as MsgType.Image | MsgType.Video, body: c.body ?? '', + filename, + caption, sender: getSenderName(room, ev.getSender() ?? ''), ts: ev.getTs(), eventId: ev.getId() ?? '', @@ -209,7 +220,7 @@ function LightboxMedia({ ) : ( {item.body} - {item.body || (item.msgtype === MsgType.Video ? 'Video' : 'Image')} + {item.filename || item.body || (item.msgtype === MsgType.Video ? 'Video' : 'Image')} {item.sender} · {dateStr} @@ -412,7 +423,7 @@ export function Lightbox({ {(ref) => ( )} + {item.caption && ( + // [Gitea #164] The full caption, readable — the header only has room + // for one truncated line. + + + {item.caption} + + + )}