From cc9f0a5730bd88c33facd6f476d0c6f318a2e869 Mon Sep 17 00:00:00 2001 From: TerryM Date: Sat, 30 May 2026 15:42:13 +0800 Subject: [PATCH] fix(stream): preserve filename extension in narrow bubbles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the file bubble wrapped JS middle-ellipsis in CSS truncate, so narrow containers silently clipped the tail+extension, leaving e.g. "25cb264a-e06…." instead of "25cb264a-e06…811a.jpg". Split the displayed name into a shrinking head (with CSS truncate) and a non-shrinking tail (last 4 base chars + extension). The browser now decides how much head to clip while the suffix is always visible. --- .../messageStream/bubbles/FileDocBubble.tsx | 20 +++++++++++++------ .../messageStream/utils/filenameDisplay.ts | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/messageStream/bubbles/FileDocBubble.tsx b/src/components/messageStream/bubbles/FileDocBubble.tsx index 42837ca..de9366a 100644 --- a/src/components/messageStream/bubbles/FileDocBubble.tsx +++ b/src/components/messageStream/bubbles/FileDocBubble.tsx @@ -5,10 +5,7 @@ import { useI18n } from "../../../i18n"; import type { Attachment, Post } from "../../../types/post"; import { downloadAttachment } from "../utils/downloadFile"; import { fileIcon } from "../utils/fileIcon"; -import { - filenameWithExtension, - middleEllipsisFilename, -} from "../utils/filenameDisplay"; +import { filenameWithExtension, splitFilename } from "../utils/filenameDisplay"; import { formatBytes } from "../utils/formatBytes"; import { postDisplayText } from "../utils/postText"; import { CollapsibleText } from "../CollapsibleText"; @@ -60,10 +57,21 @@ function AttachmentRow({ postId, att }: { postId: string; att: Attachment }) { )}
- {middleEllipsisFilename(displayFilename)} + {(() => { + const { base, ext } = splitFilename(displayFilename); + const tailChars = Math.min(4, base.length); + const head = base.slice(0, base.length - tailChars); + const tail = base.slice(base.length - tailChars) + ext; + return ( + <> + {head} + {tail} + + ); + })()}
{isDownloading ? t("downloading") : formatBytes(att.sizeBytes)} diff --git a/src/components/messageStream/utils/filenameDisplay.ts b/src/components/messageStream/utils/filenameDisplay.ts index e9da4ff..8a58b95 100644 --- a/src/components/messageStream/utils/filenameDisplay.ts +++ b/src/components/messageStream/utils/filenameDisplay.ts @@ -51,7 +51,7 @@ export function middleEllipsisFilename( return `${base.slice(0, headLength)}${ellipsis}${base.slice(-tailLength)}${ext}`; } -function splitFilename(filename: string): { base: string; ext: string } { +export function splitFilename(filename: string): { base: string; ext: string } { const dotIndex = filename.lastIndexOf("."); if (!hasFileExtension(filename)) return { base: filename, ext: "" }; return {