From a76f52228dda93425ccc8e79e8ed0eb3e741c00f Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Mon, 3 Jan 2022 00:07:48 +0800 Subject: [PATCH] feat: parse width and height when upload image and render image --- .../com.msgbyte.bbcode/src/tags/ImgTag.tsx | 38 +++++++++++++++++-- .../com.msgbyte.draw/src/DrawModal.tsx | 2 +- .../components/ChatBox/ChatInputBox/Addon.tsx | 6 ++- .../components/ChatBox/ChatInputBox/index.tsx | 4 +- .../components/ChatBox/ChatInputBox/utils.tsx | 14 +++++-- .../modals/ImageUploadPreviewer.tsx | 30 +++++++++++++-- 6 files changed, 79 insertions(+), 15 deletions(-) diff --git a/web/plugins/com.msgbyte.bbcode/src/tags/ImgTag.tsx b/web/plugins/com.msgbyte.bbcode/src/tags/ImgTag.tsx index a1d1ca1d..eeb84536 100644 --- a/web/plugins/com.msgbyte.bbcode/src/tags/ImgTag.tsx +++ b/web/plugins/com.msgbyte.bbcode/src/tags/ImgTag.tsx @@ -2,17 +2,49 @@ import React from 'react'; import { Image } from '@capital/component'; import type { TagProps } from '../bbcode/type'; +const MAX_HEIGHT = 320; +const MAX_WIDTH = 320; + const imageStyle: React.CSSProperties = { - maxHeight: 320, - maxWidth: 320, + maxHeight: MAX_HEIGHT, + maxWidth: MAX_WIDTH, width: 'auto', }; +function parseImageAttr(attr: { height: string; width: string }): { + height?: number; + width?: number; +} { + const height = Number(attr.height); + const width = Number(attr.width); + + if (!(height > 0 && width > 0)) { + // 确保宽高为数字且均大于0 + return {}; + } + + const ratio = Math.max(height / MAX_HEIGHT, width / MAX_WIDTH); + + return { + height: height / ratio, + width: width / ratio, + }; +} + export const ImgTag: React.FC = React.memo((props) => { const { node } = props; const text = node.content.join(''); const url = node.attrs.url ?? text; - return ; + return ( + + ); }); ImgTag.displayName = 'ImgTag'; diff --git a/web/plugins/com.msgbyte.draw/src/DrawModal.tsx b/web/plugins/com.msgbyte.draw/src/DrawModal.tsx index e9f6c627..4dbe9560 100644 --- a/web/plugins/com.msgbyte.draw/src/DrawModal.tsx +++ b/web/plugins/com.msgbyte.draw/src/DrawModal.tsx @@ -33,7 +33,7 @@ const DrawModal: React.FC<{ const file = dataUrlToFile(dataUrl); const res = await uploadFile(file); - sendMsg(`[img]${res.url}[/img]`); + sendMsg(`[img width=400 height=400]${res.url}[/img]`); onSuccess(); }, [sendMsg, onSuccess]); diff --git a/web/src/components/ChatBox/ChatInputBox/Addon.tsx b/web/src/components/ChatBox/ChatInputBox/Addon.tsx index 1b477aed..c915f6a5 100644 --- a/web/src/components/ChatBox/ChatInputBox/Addon.tsx +++ b/web/src/components/ChatBox/ChatInputBox/Addon.tsx @@ -18,9 +18,11 @@ export const ChatInputAddon: React.FC = React.memo(() => { const image = files[0]; if (image) { // 发送图片 - uploadMessageImage(image).then((imageRemoteUrl) => { + uploadMessageImage(image).then(({ url, width, height }) => { // TODO: not good, should bind with plugin bbcode - actionContext.sendMsg(`[img]${imageRemoteUrl}[/img]`); + actionContext.sendMsg( + `[img width=${width} height=${height}]${url}[/img]` + ); }); } }; diff --git a/web/src/components/ChatBox/ChatInputBox/index.tsx b/web/src/components/ChatBox/ChatInputBox/index.tsx index e2b02150..26f88cd5 100644 --- a/web/src/components/ChatBox/ChatInputBox/index.tsx +++ b/web/src/components/ChatBox/ChatInputBox/index.tsx @@ -36,9 +36,9 @@ export const ChatInputBox: React.FC = React.memo((props) => { if (image) { // 上传图片 e.preventDefault(); - uploadMessageImage(image).then((imageRemoteUrl) => { + uploadMessageImage(image).then(({ url, width, height }) => { // TODO: not good, should bind with plugin bbcode - props.onSendMsg(`[img]${imageRemoteUrl}[/img]`); + props.onSendMsg(`[img width=${width} height=${height}]${url}[/img]`); }); } }, diff --git a/web/src/components/ChatBox/ChatInputBox/utils.tsx b/web/src/components/ChatBox/ChatInputBox/utils.tsx index 24ce28bd..fd473b5b 100644 --- a/web/src/components/ChatBox/ChatInputBox/utils.tsx +++ b/web/src/components/ChatBox/ChatInputBox/utils.tsx @@ -7,7 +7,11 @@ import { uploadFile } from 'tailchat-shared'; /** * 上传聊天图片,并返回图片地址 */ -export function uploadMessageImage(image: File): Promise { +export function uploadMessageImage(image: File): Promise<{ + url: string; + width: number; + height: number; +}> { return new Promise((resolve) => { fileToDataUrl(image).then((imageLocalUrl) => { const key = openModal( @@ -16,11 +20,15 @@ export function uploadMessageImage(image: File): Promise { onCancel={() => { closeModal(key); }} - onConfirm={async () => { + onConfirm={async (size) => { const fileInfo = await uploadFile(image); const imageRemoteUrl = fileInfo.url; - resolve(imageRemoteUrl); + resolve({ + url: imageRemoteUrl, + width: size.width, + height: size.height, + }); closeModal(key); }} /> diff --git a/web/src/components/modals/ImageUploadPreviewer.tsx b/web/src/components/modals/ImageUploadPreviewer.tsx index 7b7f449d..3507ac8c 100644 --- a/web/src/components/modals/ImageUploadPreviewer.tsx +++ b/web/src/components/modals/ImageUploadPreviewer.tsx @@ -1,22 +1,28 @@ import { ModalWrapper } from '@/plugin/common'; import { Button } from '@/plugin/component'; -import React from 'react'; +import React, { useCallback, useRef } from 'react'; import { t, useAsyncFn } from 'tailchat-shared'; import { useGlobalKeyDown } from '../../hooks/useGlobalKeyDown'; import { isEnterHotkey, isEscHotkey } from '../../utils/hot-key'; +interface ImageSize { + width: number; + height: number; +} + interface ImageUploadPreviewerProps { imageUrl: string; - onConfirm: () => void; + onConfirm: (imageSize: ImageSize) => Promise; onCancel: () => void; } export const ImageUploadPreviewer: React.FC = React.memo((props) => { const { imageUrl } = props; + const imageSizeRef = useRef({ width: 0, height: 0 }); const [{ loading }, handleConfirm] = useAsyncFn(async () => { if (typeof props.onConfirm === 'function') { - await Promise.resolve(props.onConfirm()); + await Promise.resolve(props.onConfirm(imageSizeRef.current)); } }, [props.onConfirm]); @@ -35,11 +41,27 @@ export const ImageUploadPreviewer: React.FC = } ); + const handleLoad = useCallback( + (e: React.SyntheticEvent) => { + const target = e.currentTarget; + + imageSizeRef.current = { + width: target.naturalWidth, + height: target.naturalHeight, + }; + }, + [] + ); + return (
- +