feat: update release notes and add image preview component

- Updated release notes to reflect changes including image preview and download.
- Added interactive image preview component with toolbar for rotation, zooming, and downloading.
- Added support for image previews in Markdown rendering.
- Added functionality to download files from a URL with automatic filename detection and handling.
This commit is contained in:
kangfenmao 2024-10-12 09:53:20 +08:00
parent 85152cbcd7
commit d41667b599
4 changed files with 127 additions and 5 deletions

View File

@ -65,10 +65,7 @@ afterSign: scripts/notarize.js
releaseInfo:
releaseNotes: |
本次更新:
支持更多的数学公式显示
可以通过搜索快速切换模型
增加 Bolt 小程序
修复 Azure OpenAI 默认模型无法使用问题
支持图片的预览和下载
近期更新:
增加 WebDAV 备份功能 by @DrayChou
增加话题历史记录

View File

@ -0,0 +1,62 @@
import {
DownloadOutlined,
RotateLeftOutlined,
RotateRightOutlined,
SwapOutlined,
UndoOutlined,
ZoomInOutlined,
ZoomOutOutlined
} from '@ant-design/icons'
import { download } from '@renderer/utils/download'
import { Image, Space } from 'antd'
import React from 'react'
import styled from 'styled-components'
interface ImagePreviewProps extends React.ImgHTMLAttributes<HTMLImageElement> {
src: string
}
const ImagePreview: React.FC<ImagePreviewProps> = ({ src }) => {
return (
<Image
src={src}
preview={{
toolbarRender: (
_,
{
transform: { scale },
actions: { onFlipY, onFlipX, onRotateLeft, onRotateRight, onZoomOut, onZoomIn, onReset }
}
) => (
<ToobarWrapper size={12} className="toolbar-wrapper">
<SwapOutlined rotate={90} onClick={onFlipY} />
<SwapOutlined onClick={onFlipX} />
<RotateLeftOutlined onClick={onRotateLeft} />
<RotateRightOutlined onClick={onRotateRight} />
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
<UndoOutlined onClick={onReset} />
<DownloadOutlined onClick={() => download(src)} />
</ToobarWrapper>
)
}}
/>
)
}
const ToobarWrapper = styled(Space)`
padding: 0px 24px;
color: #fff;
font-size: 20px;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 100px;
.anticon {
padding: 12px;
cursor: pointer;
}
.anticon:hover {
opacity: 0.3;
}
`
export default ImagePreview

View File

@ -14,6 +14,7 @@ import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import CodeBlock from './CodeBlock'
import ImagePreview from './ImagePreview'
import Link from './Link'
interface Props {
@ -25,7 +26,8 @@ const remarkPlugins = [remarkMath, remarkGfm]
const components = {
code: CodeBlock,
a: Link
a: Link,
img: ImagePreview
}
const Markdown: FC<Props> = ({ message }) => {

View File

@ -0,0 +1,61 @@
export const download = (url: string) => {
fetch(url)
.then((response) => {
// 尝试从Content-Disposition头获取文件名
const contentDisposition = response.headers.get('Content-Disposition')
let filename = 'download' // 默认文件名
if (contentDisposition) {
const filenameMatch = contentDisposition.match(/filename="?(.+)"?/i)
if (filenameMatch) {
filename = filenameMatch[1]
}
}
// 如果URL中有文件名使用URL中的文件名
const urlFilename = url.split('/').pop()
if (urlFilename && urlFilename.includes('.')) {
filename = urlFilename
}
// 如果文件名没有后缀根据Content-Type添加后缀
if (!filename.includes('.')) {
const contentType = response.headers.get('Content-Type')
const extension = getExtensionFromMimeType(contentType)
filename += extension
}
// 添加时间戳以确保文件名唯一
const timestamp = Date.now()
const finalFilename = `${timestamp}_${filename}`
return response.blob().then((blob) => ({ blob, finalFilename }))
})
.then(({ blob, finalFilename }) => {
const blobUrl = URL.createObjectURL(new Blob([blob]))
const link = document.createElement('a')
link.href = blobUrl
link.download = finalFilename
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(blobUrl)
link.remove()
})
}
// 辅助函数根据MIME类型获取文件扩展名
function getExtensionFromMimeType(mimeType: string | null): string {
if (!mimeType) return '.bin' // 默认二进制文件扩展名
const mimeToExtension: { [key: string]: string } = {
'image/jpeg': '.jpg',
'image/png': '.png',
'image/gif': '.gif',
'application/pdf': '.pdf',
'text/plain': '.txt',
'application/msword': '.doc',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx'
}
return mimeToExtension[mimeType] || '.bin'
}