| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  | 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={`
 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           relative flex h-8 items-center justify-center rounded-lg bg-components-button-tertiary-bg px-3 text-xs text-text-tertiary hover:bg-components-button-tertiary-bg-hover | 
					
						
							| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  |           ${disabled ? 'cursor-not-allowed' : 'cursor-pointer'} | 
					
						
							|  |  |  |         `}>
 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |           <Link03 className='mr-2 h-4 w-4' /> | 
					
						
							| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  |           {t('common.imageUploader.pasteImageLink')} | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |       </PortalToFollowElemTrigger> | 
					
						
							|  |  |  |       <PortalToFollowElemContent className='z-10'> | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |         <div className='w-[320px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-2 shadow-lg'> | 
					
						
							| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  |           <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={`
 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             flex h-8 cursor-pointer items-center justify-center rounded-lg   | 
					
						
							|  |  |  |             bg-components-button-tertiary-bg px-3 text-xs text-text-tertiary | 
					
						
							| 
									
										
										
										
											2025-03-03 14:44:51 +08:00
										 |  |  |             ${hovering && 'hover:bg-components-button-tertiary-bg-hover'} | 
					
						
							| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  |           `}>
 | 
					
						
							| 
									
										
										
										
											2025-03-21 17:41:03 +08:00
										 |  |  |             <ImagePlus className='mr-2 h-4 w-4' /> | 
					
						
							| 
									
										
										
										
											2023-11-13 22:32:39 +08:00
										 |  |  |             {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 |