Spaces:
Build error
Build error
import { | |
memo, | |
useState, | |
} from 'react' | |
import { useTranslation } from 'react-i18next' | |
import { RiUploadCloud2Line } from '@remixicon/react' | |
import FileInput from '../file-input' | |
import { useFile } from '../hooks' | |
import { useStore } from '../store' | |
import { FILE_URL_REGEX } from '../constants' | |
import { | |
PortalToFollowElem, | |
PortalToFollowElemContent, | |
PortalToFollowElemTrigger, | |
} from '@/app/components/base/portal-to-follow-elem' | |
import Button from '@/app/components/base/button' | |
import type { FileUpload } from '@/app/components/base/features/types' | |
import cn from '@/utils/classnames' | |
type FileFromLinkOrLocalProps = { | |
showFromLink?: boolean | |
showFromLocal?: boolean | |
trigger: (open: boolean) => React.ReactNode | |
fileConfig: FileUpload | |
} | |
const FileFromLinkOrLocal = ({ | |
showFromLink = true, | |
showFromLocal = true, | |
trigger, | |
fileConfig, | |
}: FileFromLinkOrLocalProps) => { | |
const { t } = useTranslation() | |
const files = useStore(s => s.files) | |
const [open, setOpen] = useState(false) | |
const [url, setUrl] = useState('') | |
const [showError, setShowError] = useState(false) | |
const { handleLoadFileFromLink } = useFile(fileConfig) | |
const disabled = !!fileConfig.number_limits && files.length >= fileConfig.number_limits | |
const handleSaveUrl = () => { | |
if (!url) | |
return | |
if (!FILE_URL_REGEX.test(url)) { | |
setShowError(true) | |
return | |
} | |
handleLoadFileFromLink(url) | |
setUrl('') | |
} | |
return ( | |
<PortalToFollowElem | |
placement='top' | |
offset={4} | |
open={open} | |
onOpenChange={setOpen} | |
> | |
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)} asChild> | |
{trigger(open)} | |
</PortalToFollowElemTrigger> | |
<PortalToFollowElemContent className='z-10'> | |
<div className='p-3 w-[280px] bg-components-panel-bg-blur border-[0.5px] border-components-panel-border rounded-xl shadow-lg'> | |
{ | |
showFromLink && ( | |
<> | |
<div className={cn( | |
'flex items-center p-1 h-8 bg-components-input-bg-active border border-components-input-border-active rounded-lg shadow-xs', | |
showError && 'border-components-input-border-destructive', | |
)}> | |
<input | |
className='grow block mr-0.5 px-1 bg-transparent system-sm-regular outline-none appearance-none' | |
placeholder={t('common.fileUploader.pasteFileLinkInputPlaceholder') || ''} | |
value={url} | |
onChange={(e) => { | |
setShowError(false) | |
setUrl(e.target.value) | |
}} | |
disabled={disabled} | |
/> | |
<Button | |
className='shrink-0' | |
size='small' | |
variant='primary' | |
disabled={!url || disabled} | |
onClick={handleSaveUrl} | |
> | |
{t('common.operation.ok')} | |
</Button> | |
</div> | |
{ | |
showError && ( | |
<div className='mt-0.5 body-xs-regular text-text-destructive'> | |
{t('common.fileUploader.pasteFileLinkInvalid')} | |
</div> | |
) | |
} | |
</> | |
) | |
} | |
{ | |
showFromLink && showFromLocal && ( | |
<div className='flex items-center p-2 h-7 system-2xs-medium-uppercase text-text-quaternary'> | |
<div className='mr-2 w-[93px] h-[1px] bg-gradient-to-l from-[rgba(16,24,40,0.08)]' /> | |
OR | |
<div className='ml-2 w-[93px] h-[1px] bg-gradient-to-r from-[rgba(16,24,40,0.08)]' /> | |
</div> | |
) | |
} | |
{ | |
showFromLocal && ( | |
<Button | |
className='relative w-full' | |
variant='secondary-accent' | |
disabled={disabled} | |
> | |
<RiUploadCloud2Line className='mr-1 w-4 h-4' /> | |
{t('common.fileUploader.uploadFromComputer')} | |
<FileInput fileConfig={fileConfig} /> | |
</Button> | |
) | |
} | |
</div> | |
</PortalToFollowElemContent> | |
</PortalToFollowElem> | |
) | |
} | |
export default memo(FileFromLinkOrLocal) | |