From 565784b4bbe4423a10e3be850dc187bd9277dde0 Mon Sep 17 00:00:00 2001 From: TerryM Date: Wed, 27 May 2026 12:58:35 +0800 Subject: [PATCH 1/2] Shrink non-media message bubbles to content --- src/components/messageStream/MessageBubble.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/messageStream/MessageBubble.tsx b/src/components/messageStream/MessageBubble.tsx index 00fafad..0cb931f 100644 --- a/src/components/messageStream/MessageBubble.tsx +++ b/src/components/messageStream/MessageBubble.tsx @@ -27,11 +27,18 @@ export function MessageBubble({ post }: { post: Post }) { const { lang } = useI18n(); const Bubble = pickBubble(post); const isTextOnly = post.attachments.length === 0; + const isVisual = post.attachments.some( + (a) => a.kind === "image" || a.kind === "video", + ); return (
+ ); } diff --git a/src/components/messageStream/utils/downloadFile.ts b/src/components/messageStream/utils/downloadFile.ts index 99d2fdf..c9050a4 100644 --- a/src/components/messageStream/utils/downloadFile.ts +++ b/src/components/messageStream/utils/downloadFile.ts @@ -1,27 +1,5 @@ import { assetUrl } from "../../../api"; -type SaveFilePicker = (options?: { - suggestedName?: string; - types?: Array<{ - description?: string; - accept: Record; - }>; -}) => Promise<{ - createWritable: () => Promise<{ - write: (data: Blob) => Promise; - close: () => Promise; - }>; -}>; - -type NavigatorWithFileShare = Navigator & { - canShare?: (data: { files?: File[] }) => boolean; - share?: (data: { files?: File[]; title?: string }) => Promise; -}; - -type WindowWithSavePicker = Window & { - showSaveFilePicker?: SaveFilePicker; -}; - export function attachmentDownloadUrl(postId: string, attachmentId: string) { return assetUrl( `/api/posts/${encodeURIComponent(postId)}/attachments/${encodeURIComponent( @@ -39,45 +17,7 @@ export async function downloadAttachment( } export async function downloadFile(url: string, filename: string) { - const res = await fetch(url, { credentials: "include" }); - if (!res.ok) throw new Error(await res.text()); - - const blob = await res.blob(); - const safeName = filename || "download"; - - if (window.isSecureContext) { - const picker = (window as WindowWithSavePicker).showSaveFilePicker; - if (picker) { - const handle = await picker({ - suggestedName: safeName, - types: blob.type - ? [ - { - description: "File", - accept: { [blob.type]: [extensionFromName(safeName)] }, - }, - ] - : undefined, - }); - const writable = await handle.createWritable(); - await writable.write(blob); - await writable.close(); - return; - } - } - - const file = new File([blob], safeName, { - type: blob.type || "application/octet-stream", - }); - const nav = navigator as NavigatorWithFileShare; - if (nav.canShare?.({ files: [file] }) && nav.share) { - await nav.share({ files: [file], title: safeName }); - return; - } - - const objectUrl = URL.createObjectURL(blob); - triggerDownload(objectUrl, safeName); - window.setTimeout(() => URL.revokeObjectURL(objectUrl), 30_000); + triggerDownload(url, filename || "download"); } function triggerDownload(url: string, filename: string) { @@ -89,8 +29,3 @@ function triggerDownload(url: string, filename: string) { a.click(); a.remove(); } - -function extensionFromName(filename: string) { - const match = /\.[^.]+$/.exec(filename); - return match?.[0] || ".bin"; -} -- 2.49.1