fix(ImageViewer): prevent double menu, improve icons (#9637)

* fix(ImageViewer): prevent double menu, improve icons

* refactor: default icon size, standard error messages
This commit is contained in:
one 2025-08-29 00:25:58 +08:00 committed by GitHub
parent 649a2a645c
commit 95ff67e99c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,7 +1,6 @@
import { import {
CopyOutlined, CopyOutlined,
DownloadOutlined, DownloadOutlined,
FileImageOutlined,
RotateLeftOutlined, RotateLeftOutlined,
RotateRightOutlined, RotateRightOutlined,
SwapOutlined, SwapOutlined,
@ -13,11 +12,14 @@ import { loggerService } from '@logger'
import { download } from '@renderer/utils/download' import { download } from '@renderer/utils/download'
import { Dropdown, Image as AntImage, ImageProps as AntImageProps, Space } from 'antd' import { Dropdown, Image as AntImage, ImageProps as AntImageProps, Space } from 'antd'
import { Base64 } from 'js-base64' import { Base64 } from 'js-base64'
import { DownloadIcon, ImageIcon } from 'lucide-react'
import mime from 'mime' import mime from 'mime'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import { CopyIcon } from './Icons'
interface ImageViewerProps extends AntImageProps { interface ImageViewerProps extends AntImageProps {
src: string src: string
} }
@ -33,7 +35,7 @@ const ImageViewer: React.FC<ImageViewerProps> = ({ src, style, ...props }) => {
if (src.startsWith('data:')) { if (src.startsWith('data:')) {
// 处理 base64 格式的图片 // 处理 base64 格式的图片
const match = src.match(/^data:(image\/\w+);base64,(.+)$/) const match = src.match(/^data:(image\/\w+);base64,(.+)$/)
if (!match) throw new Error('无效的 base64 图片格式') if (!match) throw new Error('Invalid base64 image format')
const mimeType = match[1] const mimeType = match[1]
const byteArray = Base64.toUint8Array(match[2]) const byteArray = Base64.toUint8Array(match[2])
const blob = new Blob([byteArray], { type: mimeType }) const blob = new Blob([byteArray], { type: mimeType })
@ -62,17 +64,17 @@ const ImageViewer: React.FC<ImageViewerProps> = ({ src, style, ...props }) => {
window.message.success(t('message.copy.success')) window.message.success(t('message.copy.success'))
} catch (error) { } catch (error) {
logger.error('复制图片失败:', error as Error) logger.error('Failed to copy image:', error as Error)
window.message.error(t('message.copy.failed')) window.message.error(t('message.copy.failed'))
} }
} }
const getContextMenuItems = (src: string) => { const getContextMenuItems = (src: string, size: number = 14) => {
return [ return [
{ {
key: 'copy-url', key: 'copy-url',
label: t('common.copy'), label: t('common.copy'),
icon: <CopyOutlined />, icon: <CopyIcon size={size} />,
onClick: () => { onClick: () => {
navigator.clipboard.writeText(src) navigator.clipboard.writeText(src)
window.message.success(t('message.copy.success')) window.message.success(t('message.copy.success'))
@ -81,13 +83,13 @@ const ImageViewer: React.FC<ImageViewerProps> = ({ src, style, ...props }) => {
{ {
key: 'download', key: 'download',
label: t('common.download'), label: t('common.download'),
icon: <DownloadOutlined />, icon: <DownloadIcon size={size} />,
onClick: () => download(src) onClick: () => download(src)
}, },
{ {
key: 'copy-image', key: 'copy-image',
label: t('preview.copy.image'), label: t('preview.copy.image'),
icon: <FileImageOutlined />, icon: <ImageIcon size={size} />,
onClick: () => handleCopyImage(src) onClick: () => handleCopyImage(src)
} }
] ]
@ -98,6 +100,7 @@ const ImageViewer: React.FC<ImageViewerProps> = ({ src, style, ...props }) => {
<AntImage <AntImage
src={src} src={src}
style={style} style={style}
onContextMenu={(e) => e.stopPropagation()}
{...props} {...props}
preview={{ preview={{
mask: typeof props.preview === 'object' ? props.preview.mask : false, mask: typeof props.preview === 'object' ? props.preview.mask : false,