From 1da644643739285ce68b0266719ff811a2c30e8f Mon Sep 17 00:00:00 2001 From: qer Date: Fri, 3 Jul 2026 13:29:35 +0800 Subject: [PATCH] feat(web): enlarge user message images on click Wrap user-message image thumbnails in a button that opens the existing image preview panel, matching the tool-result image behavior. Adds the en/zh aria-label and resets the button chrome so the thumbnail looks unchanged. --- .changeset/web-user-image-preview.md | 5 ++ .../kimi-web/src/components/chat/ChatPane.vue | 73 +++++++++++++++---- .../src/i18n/locales/en/filePreview.ts | 1 + .../src/i18n/locales/zh/filePreview.ts | 1 + 4 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 .changeset/web-user-image-preview.md diff --git a/.changeset/web-user-image-preview.md b/.changeset/web-user-image-preview.md new file mode 100644 index 000000000..0ead805e5 --- /dev/null +++ b/.changeset/web-user-image-preview.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": minor +--- + +Click an image in a user message to open its full-size preview in the web chat. diff --git a/apps/kimi-web/src/components/chat/ChatPane.vue b/apps/kimi-web/src/components/chat/ChatPane.vue index d61495293..71c09c1ca 100644 --- a/apps/kimi-web/src/components/chat/ChatPane.vue +++ b/apps/kimi-web/src/components/chat/ChatPane.vue @@ -8,6 +8,7 @@ import ToolGroup from './ToolGroup.vue'; import Markdown from './Markdown.vue'; import ThinkingBlock from './ThinkingBlock.vue'; import ActivityNotice from './ActivityNotice.vue'; +import AuthMedia from './AuthMedia.vue'; import MoonSpinner from '../ui/MoonSpinner.vue'; import Spinner from '../ui/Spinner.vue'; import Icon from '../ui/Icon.vue'; @@ -487,6 +488,12 @@ function copyUserMessage(turn: ChatTurn): void { }).catch(() => {/* ignore */}); } +function userImageMedia(img: { url: string; alt?: string }): ToolMedia { + // User-uploaded images carry no path/mime metadata; the preview panel falls + // back to a generic label and sniffs the mime from the URL when needed. + return { kind: 'image', url: img.url, path: img.alt }; +} + function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }): boolean { if (turn.id !== streamingTurnId.value) return false; return block.sourceIndex === turnBlocks(turn).length - 1; @@ -537,21 +544,28 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }):
@@ -716,10 +730,16 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }):
- +
{{ t('composer.queueNext') }} #{{ qi + 1 }} @@ -1078,6 +1098,27 @@ function isStreamingRenderBlock(turn: ChatTurn, block: { sourceIndex: number }): border-radius: 8px; object-fit: cover; } +/* Clickable image thumbnail — reset button chrome so it looks like the plain + image it replaced, while still opening the preview on click. */ +.u-img-btn { + display: block; + flex: none; + align-self: flex-start; + max-width: 100%; + padding: 0; + border: none; + background: transparent; + cursor: pointer; + border-radius: 8px; + overflow: hidden; +} +.u-img-btn .u-img { + display: block; +} +.u-img-btn:focus-visible { + outline: none; + box-shadow: var(--p-focus-ring); +} /* NOTE: Chat/bubble styles live in src/style.css (global). Scoped `.u-bub` rules here did NOT win the cascade, so they were moved to the global sheet. */ diff --git a/apps/kimi-web/src/i18n/locales/en/filePreview.ts b/apps/kimi-web/src/i18n/locales/en/filePreview.ts index 5855db8b8..2eb11d72e 100644 --- a/apps/kimi-web/src/i18n/locales/en/filePreview.ts +++ b/apps/kimi-web/src/i18n/locales/en/filePreview.ts @@ -24,6 +24,7 @@ export default { binaryNoPreview: 'Binary file · {mime} · {size} bytes · preview unavailable', unknownType: 'unknown type', copyCode: 'Copy code', + enlargeImage: 'Enlarge image', errors: { emptyPath: 'File path is empty', unsupportedPath: 'URLs and remote paths cannot be previewed', diff --git a/apps/kimi-web/src/i18n/locales/zh/filePreview.ts b/apps/kimi-web/src/i18n/locales/zh/filePreview.ts index 753d2bf62..0906e93d4 100644 --- a/apps/kimi-web/src/i18n/locales/zh/filePreview.ts +++ b/apps/kimi-web/src/i18n/locales/zh/filePreview.ts @@ -24,6 +24,7 @@ export default { binaryNoPreview: '二进制文件 · {mime} · {size} 字节 · 暂不预览', unknownType: '未知类型', copyCode: '复制代码', + enlargeImage: '放大图片', errors: { emptyPath: '文件路径为空', unsupportedPath: '不支持预览 URL 或远程路径',