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