| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 | 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
 |