import type { Area } from 'react-easy-crop' import type { OnImageInput } from './ImageInput' import type { AppIconType, ImageFile } from '@/types/app' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Dialog, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog' import { RiImageCircleAiLine } from '@remixicon/react' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config' import Divider from '../divider' import { defaultEmojiBackground } from '../emoji-picker/constants' import EmojiPickerInner from '../emoji-picker/Inner' import { useLocalFileUploader } from '../image-uploader/hooks' import ImageInput from './ImageInput' import s from './style.module.css' import getCroppedImg from './utils' export type AppIconEmojiSelection = { type: 'emoji' icon: string background: string } export type AppIconImageSelection = { type: 'image' fileId: string url: string } export type AppIconSelection = AppIconEmojiSelection | AppIconImageSelection type AppIconPickerProps = { open: boolean onOpenChange: (open: boolean) => void onSelect?: (payload: AppIconSelection) => void enableImageUpload?: boolean initialEmoji?: { icon: string background?: string | null } className?: string } function AppIconPicker({ open, onOpenChange, onSelect, enableImageUpload = true, initialEmoji, className, }: AppIconPickerProps) { return ( {open ? ( ) : null} ) } type AppIconPickerContentProps = { className?: string initialEmoji?: { icon: string background?: string | null } enableImageUpload: boolean onOpenChange: (open: boolean) => void onSelect?: (payload: AppIconSelection) => void } function AppIconPickerContent({ className, initialEmoji, enableImageUpload, onOpenChange, onSelect, }: AppIconPickerContentProps) { const { t } = useTranslation() const tabs = [ { key: 'emoji', label: t(($) => $['iconPicker.emoji'], { ns: 'app' }), icon: 🤖, }, { key: 'image', label: t(($) => $['iconPicker.image'], { ns: 'app' }), icon: , }, ] const [activeTab, setActiveTab] = useState('emoji') const showImageUpload = enableImageUpload && !DISABLE_UPLOAD_IMAGE_AS_ICON const [emoji, setEmoji] = useState<{ emoji: string; background: string } | undefined>(() => { if (!initialEmoji?.icon) return undefined return { emoji: initialEmoji.icon, background: initialEmoji.background ?? defaultEmojiBackground, } }) const [uploading, setUploading] = useState() const { handleLocalFileUpload } = useLocalFileUploader({ limit: 3, disabled: false, onUpload: (imageFile: ImageFile) => { if (imageFile.fileId) { setUploading(false) onSelect?.({ type: 'image', fileId: imageFile.fileId, url: imageFile.url, }) onOpenChange(false) } }, }) type InputImageInfo = | { file: File } | { tempUrl: string; croppedAreaPixels: Area; fileName: string } const [inputImageInfo, setInputImageInfo] = useState() const handleImageInput: OnImageInput = async ( isCropped: boolean, fileOrTempUrl: string | File, croppedAreaPixels?: Area, fileName?: string, ) => { setInputImageInfo( isCropped ? { tempUrl: fileOrTempUrl as string, croppedAreaPixels: croppedAreaPixels!, fileName: fileName!, } : { file: fileOrTempUrl as File }, ) } const handleSelect = async () => { if (activeTab === 'emoji') { if (emoji) { onSelect?.({ type: 'emoji', icon: emoji.emoji, background: emoji.background, }) onOpenChange(false) } } else { if (!inputImageInfo) return setUploading(true) if ('file' in inputImageInfo) { handleLocalFileUpload(inputImageInfo.file) return } const blob = await getCroppedImg( inputImageInfo.tempUrl, inputImageInfo.croppedAreaPixels, inputImageInfo.fileName, ) const file = new File([blob], inputImageInfo.fileName, { type: blob.type }) handleLocalFileUpload(file) } } return ( {t(($) => $['iconPicker.emoji'], { ns: 'app' })} {showImageUpload && ( {tabs.map((tab) => ( setActiveTab(tab.key as AppIconType)} > {tab.icon} {tab.label} ))} )} {activeTab === 'emoji' && ( setEmoji({ emoji, background })} /> )} {activeTab === 'image' && ( )} onOpenChange(false)}> {t(($) => $['iconPicker.cancel'], { ns: 'app' })} {t(($) => $['iconPicker.ok'], { ns: 'app' })} ) } export default AppIconPicker