feat(webui): render image attachments inline
This commit is contained in:
parent
b043fcf531
commit
4b0d5e41c6
@ -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"));
|
||||
}
|
||||
|
||||
@ -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}
|
||||
<div class="message-attachments">
|
||||
{#each message.attachments as attachment (`${message.id}:${attachment.index}`)}
|
||||
<article class="attachment-card">
|
||||
{#if canPreview(attachment)}
|
||||
<img src={attachmentUrl(message, attachment, true)} alt={attachment.name} />
|
||||
{:else}<span class="attachment-icon">▧</span>{/if}
|
||||
<article class="image-attachment">
|
||||
<a class="image-preview-link" href={attachmentUrl(message, attachment)} target="_blank" rel="noreferrer" aria-label={`查看原图 ${attachment.name}`}>
|
||||
<img class="image-preview" src={attachmentUrl(message, attachment, true)} alt={attachment.name} />
|
||||
</a>
|
||||
<div class="attachment-meta"><div><strong>{attachment.name}</strong><small>{attachment.mime_type || attachment.media_type}</small></div><a href={attachmentUrl(message, attachment)} download={attachment.name} aria-label={`下载 ${attachment.name}`}>↓</a></div>
|
||||
</article>
|
||||
{:else}
|
||||
<article class="attachment-card">
|
||||
<span class="attachment-icon">▧</span>
|
||||
<div><strong>{attachment.name}</strong><small>{attachment.mime_type || attachment.media_type}</small></div>
|
||||
<a href={attachmentUrl(message, attachment)} download={attachment.name} aria-label={`下载 ${attachment.name}`}>↓</a>
|
||||
</article>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -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); }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user