From 4b0d5e41c63298bc4c3d7f226eec09143aeafd7b Mon Sep 17 00:00:00 2001 From: xiaoxixi Date: Mon, 20 Jul 2026 00:11:51 +0800 Subject: [PATCH] feat(webui): render image attachments inline --- src/gateway/http.rs | 4 ++++ webui/src/pages/ChatPage.svelte | 23 +++++++++++++++-------- webui/src/styles.css | 9 ++++++++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/gateway/http.rs b/src/gateway/http.rs index 2ee16bf..9cf230f 100644 --- a/src/gateway/http.rs +++ b/src/gateway/http.rs @@ -307,6 +307,9 @@ fn inline_mime_allowed(mime: &str) -> bool { | "image/jpeg" | "image/gif" | "image/webp" + | "image/bmp" + | "image/avif" + | "image/x-icon" | "audio/mpeg" | "audio/ogg" | "audio/wav" @@ -724,6 +727,7 @@ mod tests { "%E6%8A%A5%E5%91%8A%201.pdf" ); assert!(inline_mime_allowed("image/png")); + assert!(inline_mime_allowed("image/bmp")); assert!(!inline_mime_allowed("image/svg+xml")); assert!(!inline_mime_allowed("text/html")); } diff --git a/webui/src/pages/ChatPage.svelte b/webui/src/pages/ChatPage.svelte index 77550f6..353865b 100644 --- a/webui/src/pages/ChatPage.svelte +++ b/webui/src/pages/ChatPage.svelte @@ -250,7 +250,7 @@ } function canPreview(attachment) { - return ["image/png", "image/jpeg", "image/gif", "image/webp"].includes(attachment.mime_type); + return ["image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp", "image/avif", "image/x-icon"].includes(attachment.mime_type); } function addFiles(files) { @@ -439,13 +439,20 @@ {#if message.attachments?.length}
{#each message.attachments as attachment (`${message.id}:${attachment.index}`)} -
- {#if canPreview(attachment)} - {attachment.name} - {:else}{/if} -
{attachment.name}{attachment.mime_type || attachment.media_type}
- -
+ {#if canPreview(attachment)} +
+ + {attachment.name} + +
{attachment.name}{attachment.mime_type || attachment.media_type}
+
+ {:else} +
+ +
{attachment.name}{attachment.mime_type || attachment.media_type}
+ +
+ {/if} {/each}
{/if} diff --git a/webui/src/styles.css b/webui/src/styles.css index 7de62da..1561350 100644 --- a/webui/src/styles.css +++ b/webui/src/styles.css @@ -145,10 +145,17 @@ main { min-width: 0; height: 100vh; display: flex; flex-direction: column; } .message.user .bubble { background: var(--user-bubble); border-color: var(--accent-border); } .message-attachments { display: grid; gap: 7px; width: min(100%, 520px); } .attachment-card { display: grid; grid-template-columns: 42px minmax(0, 1fr) 30px; gap: 9px; align-items: center; padding: 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); } -.attachment-card img, .attachment-icon { width: 42px; height: 42px; border-radius: 7px; object-fit: cover; background: var(--panel-2); display: grid; place-items: center; color: var(--accent); } +.attachment-icon { width: 42px; height: 42px; border-radius: 7px; background: var(--panel-2); display: grid; place-items: center; color: var(--accent); } .attachment-card strong, .attachment-card small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .attachment-card strong { font-size: 12px; }.attachment-card small { margin-top: 3px; color: var(--muted); font-size: 9px; } .attachment-card a { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 7px; color: var(--accent); text-decoration: none; } +.image-attachment { width: min(100%, 680px); overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); } +.image-preview-link { display: grid; max-height: 520px; overflow: hidden; place-items: center; background: var(--panel-2); } +.image-preview { display: block; max-width: 100%; max-height: 520px; object-fit: contain; } +.attachment-meta { display: grid; grid-template-columns: minmax(0, 1fr) 30px; gap: 9px; align-items: center; padding: 8px 10px; } +.attachment-meta strong, .attachment-meta small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.attachment-meta strong { font-size: 12px; }.attachment-meta small { margin-top: 3px; color: var(--muted); font-size: 9px; } +.attachment-meta > a { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 7px; color: var(--accent); text-decoration: none; } .typing .bubble { color: var(--muted); } .active-turn .message-content { width: min(82%, 760px); } .streaming { border-color: var(--accent-border); }