diff --git a/web/app/components/base/app-icon-picker/Uploader.tsx b/web/app/components/base/app-icon-picker/Uploader.tsx index 4ddaa404475e6d..7c7da59718f437 100644 --- a/web/app/components/base/app-icon-picker/Uploader.tsx +++ b/web/app/components/base/app-icon-picker/Uploader.tsx @@ -8,12 +8,12 @@ import classNames from 'classnames' import { ImagePlus } from '../icons/src/vender/line/images' import { useDraggableUploader } from './hooks' +import { isAnimatedImage } from './utils' import { ALLOW_FILE_EXTENSIONS } from '@/types/app' type UploaderProps = { className?: string - onImageCropped?: (tempUrl: string, croppedAreaPixels: Area, fileName: string) => void -} + onImageCropped?: (tempUrl: string, croppedAreaPixels: Area, fileName: string, file?: File) => void } const Uploader: FC = ({ className, @@ -38,8 +38,11 @@ const Uploader: FC = ({ const handleLocalFileInput = (e: ChangeEvent) => { const file = e.target.files?.[0] - if (file) + if (file) { setInputImage({ file, url: URL.createObjectURL(file) }) + if (isAnimatedImage(file)) + onImageCropped?.(URL.createObjectURL(file), { x: 0, y: 0, width: 0, height: 0 }, file.name, file) + } } const { @@ -52,6 +55,25 @@ const Uploader: FC = ({ const inputRef = createRef() + const handleShowImage = () => { + if (isAnimatedImage(inputImage?.file || { name: '' })) { + return ( + + ) + } + return ( + + ) + } + return (
= ({
Supports PNG, JPG, JPEG, WEBP and GIF
- : + : handleShowImage() }
diff --git a/web/app/components/base/app-icon-picker/index.tsx b/web/app/components/base/app-icon-picker/index.tsx index 825481547501a8..805750a6176dc3 100644 --- a/web/app/components/base/app-icon-picker/index.tsx +++ b/web/app/components/base/app-icon-picker/index.tsx @@ -10,7 +10,7 @@ import { useLocalFileUploader } from '../image-uploader/hooks' import EmojiPickerInner from '../emoji-picker/Inner' import Uploader from './Uploader' import s from './style.module.css' -import getCroppedImg from './utils' +import getCroppedImg, { isAnimatedImage } from './utils' import type { AppIconType, ImageFile } from '@/types/app' import cn from '@/utils/classnames' import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config' @@ -69,9 +69,9 @@ const AppIconPicker: FC = ({ }, }) - const [imageCropInfo, setImageCropInfo] = useState<{ tempUrl: string; croppedAreaPixels: Area; fileName: string }>() - const handleImageCropped = async (tempUrl: string, croppedAreaPixels: Area, fileName: string) => { - setImageCropInfo({ tempUrl, croppedAreaPixels, fileName }) + const [imageCropInfo, setImageCropInfo] = useState<{ tempUrl: string; croppedAreaPixels: Area; fileName: string; file?: File }>() + const handleImageCropped = async (tempUrl: string, croppedAreaPixels: Area, fileName: string, file?: File) => { + setImageCropInfo({ tempUrl, croppedAreaPixels, fileName, file }) } const handleSelect = async () => { @@ -88,6 +88,10 @@ const AppIconPicker: FC = ({ if (!imageCropInfo) return setUploading(true) + if (isAnimatedImage({ name: imageCropInfo.fileName }) && imageCropInfo.file) { + handleLocalFileUpload(imageCropInfo.file) + return + } const blob = await getCroppedImg(imageCropInfo.tempUrl, imageCropInfo.croppedAreaPixels) const file = new File([blob], imageCropInfo.fileName, { type: blob.type }) handleLocalFileUpload(file) diff --git a/web/app/components/base/app-icon-picker/utils.ts b/web/app/components/base/app-icon-picker/utils.ts index 0c90e96febda83..63cce7df3986d6 100644 --- a/web/app/components/base/app-icon-picker/utils.ts +++ b/web/app/components/base/app-icon-picker/utils.ts @@ -93,6 +93,10 @@ export default async function getCroppedImg( resolve(file) else reject(new Error('Could not create a blob')) - }, 'image/jpeg') + }, 'image/png') }) } + +export function isAnimatedImage(file: { name: string }) { + return (file?.name?.endsWith('.webp') || file?.name?.endsWith('.gif')) +}