mirror of
				https://github.com/langgenius/dify.git
				synced 2025-10-31 10:53:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import type { FC } from 'react'
 | |
| import {
 | |
|   Fragment,
 | |
|   useEffect,
 | |
|   useState,
 | |
| } from 'react'
 | |
| import { useTranslation } from 'react-i18next'
 | |
| import Uploader from './uploader'
 | |
| import ImageLinkInput from './image-link-input'
 | |
| import ImageList from './image-list'
 | |
| import { useImageFiles } from './hooks'
 | |
| import { ImagePlus } from '@/app/components/base/icons/src/vender/line/images'
 | |
| import { Link03 } from '@/app/components/base/icons/src/vender/line/general'
 | |
| import {
 | |
|   PortalToFollowElem,
 | |
|   PortalToFollowElemContent,
 | |
|   PortalToFollowElemTrigger,
 | |
| } from '@/app/components/base/portal-to-follow-elem'
 | |
| import type { ImageFile, VisionSettings } from '@/types/app'
 | |
| import { TransferMethod } from '@/types/app'
 | |
| 
 | |
| type PasteImageLinkButtonProps = {
 | |
|   onUpload: (imageFile: ImageFile) => void
 | |
|   disabled?: boolean
 | |
| }
 | |
| const PasteImageLinkButton: FC<PasteImageLinkButtonProps> = ({
 | |
|   onUpload,
 | |
|   disabled,
 | |
| }) => {
 | |
|   const { t } = useTranslation()
 | |
|   const [open, setOpen] = useState(false)
 | |
| 
 | |
|   const handleUpload = (imageFile: ImageFile) => {
 | |
|     setOpen(false)
 | |
|     onUpload(imageFile)
 | |
|   }
 | |
| 
 | |
|   const handleToggle = () => {
 | |
|     if (disabled)
 | |
|       return
 | |
| 
 | |
|     setOpen(v => !v)
 | |
|   }
 | |
| 
 | |
|   return (
 | |
|     <PortalToFollowElem
 | |
|       open={open}
 | |
|       onOpenChange={setOpen}
 | |
|       placement='top-start'
 | |
|     >
 | |
|       <PortalToFollowElemTrigger onClick={handleToggle}>
 | |
|         <div className={`
 | |
|           relative flex items-center justify-center px-3 h-8 bg-gray-100 hover:bg-gray-200 text-xs text-gray-500 rounded-lg
 | |
|           ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
 | |
|         `}>
 | |
|           <Link03 className='mr-2 w-4 h-4' />
 | |
|           {t('common.imageUploader.pasteImageLink')}
 | |
|         </div>
 | |
|       </PortalToFollowElemTrigger>
 | |
|       <PortalToFollowElemContent className='z-10'>
 | |
|         <div className='p-2 w-[320px] bg-white border-[0.5px] border-gray-200 rounded-lg shadow-lg'>
 | |
|           <ImageLinkInput onUpload={handleUpload} />
 | |
|         </div>
 | |
|       </PortalToFollowElemContent>
 | |
|     </PortalToFollowElem>
 | |
|   )
 | |
| }
 | |
| 
 | |
| type TextGenerationImageUploaderProps = {
 | |
|   settings: VisionSettings
 | |
|   onFilesChange: (files: ImageFile[]) => void
 | |
| }
 | |
| const TextGenerationImageUploader: FC<TextGenerationImageUploaderProps> = ({
 | |
|   settings,
 | |
|   onFilesChange,
 | |
| }) => {
 | |
|   const { t } = useTranslation()
 | |
| 
 | |
|   const {
 | |
|     files,
 | |
|     onUpload,
 | |
|     onRemove,
 | |
|     onImageLinkLoadError,
 | |
|     onImageLinkLoadSuccess,
 | |
|     onReUpload,
 | |
|   } = useImageFiles()
 | |
| 
 | |
|   useEffect(() => {
 | |
|     onFilesChange(files)
 | |
|   }, [files])
 | |
| 
 | |
|   const localUpload = (
 | |
|     <Uploader
 | |
|       onUpload={onUpload}
 | |
|       disabled={files.length >= settings.number_limits}
 | |
|       limit={+settings.image_file_size_limit!}
 | |
|     >
 | |
|       {
 | |
|         hovering => (
 | |
|           <div className={`
 | |
|             flex items-center justify-center px-3 h-8 bg-gray-100
 | |
|             text-xs text-gray-500 rounded-lg cursor-pointer
 | |
|             ${hovering && 'bg-gray-200'}
 | |
|           `}>
 | |
|             <ImagePlus className='mr-2 w-4 h-4' />
 | |
|             {t('common.imageUploader.uploadFromComputer')}
 | |
|           </div>
 | |
|         )
 | |
|       }
 | |
|     </Uploader>
 | |
|   )
 | |
| 
 | |
|   const urlUpload = (
 | |
|     <PasteImageLinkButton
 | |
|       onUpload={onUpload}
 | |
|       disabled={files.length >= settings.number_limits}
 | |
|     />
 | |
|   )
 | |
| 
 | |
|   return (
 | |
|     <div>
 | |
|       <div className='mb-1'>
 | |
|         <ImageList
 | |
|           list={files}
 | |
|           onRemove={onRemove}
 | |
|           onReUpload={onReUpload}
 | |
|           onImageLinkLoadError={onImageLinkLoadError}
 | |
|           onImageLinkLoadSuccess={onImageLinkLoadSuccess}
 | |
|         />
 | |
|       </div>
 | |
|       <div className={`grid gap-1 ${settings.transfer_methods.length === 2 ? 'grid-cols-2' : 'grid-cols-1'}`}>
 | |
|         {
 | |
|           settings.transfer_methods.map((method) => {
 | |
|             if (method === TransferMethod.local_file)
 | |
|               return <Fragment key={TransferMethod.local_file}>{localUpload}</Fragment>
 | |
| 
 | |
|             if (method === TransferMethod.remote_url)
 | |
|               return <Fragment key={TransferMethod.remote_url}>{urlUpload}</Fragment>
 | |
| 
 | |
|             return null
 | |
|           })
 | |
|         }
 | |
|       </div>
 | |
|     </div>
 | |
|   )
 | |
| }
 | |
| 
 | |
| export default TextGenerationImageUploader
 | 
