mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-15 22:06:52 +08:00
Chore: frontend infrastructure upgrade (#16420)
Co-authored-by: NFish <douxc512@gmail.com> Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: twwu <twwu@dify.ai> Co-authored-by: jZonG <jzongcode@gmail.com>
This commit is contained in:
@@ -13,24 +13,23 @@ const AudioPreview: FC<AudioPreviewProps> = ({
|
||||
onCancel,
|
||||
}) => {
|
||||
return createPortal(
|
||||
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}>
|
||||
<div className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8' onClick={e => e.stopPropagation()}>
|
||||
<div>
|
||||
<audio controls title={title} autoPlay={false} preload="metadata">
|
||||
<source
|
||||
type="audio/mpeg"
|
||||
src={url}
|
||||
className='max-w-full max-h-full'
|
||||
className='max-h-full max-w-full'
|
||||
/>
|
||||
</audio>
|
||||
</div>
|
||||
<div
|
||||
className='absolute top-6 right-6 flex items-center justify-center w-8 h-8 bg-white/[0.08] rounded-lg backdrop-blur-[2px] cursor-pointer'
|
||||
className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
|
||||
onClick={onCancel}
|
||||
>
|
||||
<RiCloseLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiCloseLine className='h-4 w-4 text-gray-500'/>
|
||||
</div>
|
||||
</div>
|
||||
,
|
||||
</div>,
|
||||
document.body,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ const UploadOnlyFromLocal: FC<UploadOnlyFromLocalProps> = ({
|
||||
{hovering => (
|
||||
<div
|
||||
className={`
|
||||
relative flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer
|
||||
relative flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg
|
||||
${hovering && 'bg-gray-100'}
|
||||
`}
|
||||
>
|
||||
<ImagePlus className="w-4 h-4 text-gray-500" />
|
||||
<ImagePlus className="h-4 w-4 text-gray-500" />
|
||||
</div>
|
||||
)}
|
||||
</Uploader>
|
||||
@@ -82,20 +82,20 @@ const UploaderButton: FC<UploaderButtonProps> = ({
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
className="relative flex items-center justify-center w-8 h-8 enabled:hover:bg-gray-100 rounded-lg disabled:cursor-not-allowed"
|
||||
className="relative flex h-8 w-8 items-center justify-center rounded-lg enabled:hover:bg-gray-100 disabled:cursor-not-allowed"
|
||||
>
|
||||
<ImagePlus className="w-4 h-4 text-gray-500" />
|
||||
<ImagePlus className="h-4 w-4 text-gray-500" />
|
||||
</button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-50">
|
||||
<div className="p-2 w-[260px] bg-white rounded-lg border-[0.5px] border-gray-200 shadow-lg">
|
||||
<div className="w-[260px] rounded-lg border-[0.5px] border-gray-200 bg-white p-2 shadow-lg">
|
||||
<ImageLinkInput onUpload={handleUpload} disabled={disabled} />
|
||||
{hasUploadFromLocal && (
|
||||
<>
|
||||
<div className="flex items-center mt-2 px-2 text-xs font-medium text-gray-400">
|
||||
<div className="mr-3 w-[93px] h-[1px] bg-gradient-to-l from-[#F3F4F6]" />
|
||||
<div className="mt-2 flex items-center px-2 text-xs font-medium text-gray-400">
|
||||
<div className="mr-3 h-[1px] w-[93px] bg-gradient-to-l from-[#F3F4F6]" />
|
||||
OR
|
||||
<div className="ml-3 w-[93px] h-[1px] bg-gradient-to-r from-[#F3F4F6]" />
|
||||
<div className="ml-3 h-[1px] w-[93px] bg-gradient-to-r from-[#F3F4F6]" />
|
||||
</div>
|
||||
<Uploader
|
||||
onUpload={handleUpload}
|
||||
@@ -105,11 +105,11 @@ const UploaderButton: FC<UploaderButtonProps> = ({
|
||||
{hovering => (
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center justify-center h-8 text-[13px] font-medium text-[#155EEF] rounded-lg cursor-pointer',
|
||||
'flex h-8 cursor-pointer items-center justify-center rounded-lg text-[13px] font-medium text-[#155EEF]',
|
||||
hovering && 'bg-primary-50',
|
||||
)}
|
||||
>
|
||||
<Upload03 className="mr-1 w-4 h-4" />
|
||||
<Upload03 className="mr-1 h-4 w-4" />
|
||||
{t('common.imageUploader.uploadFromComputer')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -33,10 +33,10 @@ const ImageLinkInput: FC<ImageLinkInputProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex items-center pl-1.5 pr-1 h-8 border border-components-panel-border bg-components-panel-bg shadow-xs rounded-lg'>
|
||||
<div className='flex h-8 items-center rounded-lg border border-components-panel-border bg-components-panel-bg pl-1.5 pr-1 shadow-xs'>
|
||||
<input
|
||||
type="text"
|
||||
className='grow mr-0.5 px-1 h-[18px] text-[13px] text-text-primary bg-transparent outline-none appearance-none'
|
||||
className='mr-0.5 h-[18px] grow appearance-none bg-transparent px-1 text-[13px] text-text-primary outline-none'
|
||||
value={imageLink}
|
||||
onChange={e => setImageLink(e.target.value)}
|
||||
placeholder={t('common.imageUploader.pasteImageLinkInputPlaceholder') || ''}
|
||||
|
||||
@@ -51,23 +51,23 @@ const ImageList: FC<ImageListProps> = ({
|
||||
{list.map(item => (
|
||||
<div
|
||||
key={item._id}
|
||||
className="group relative mr-1 border-[0.5px] border-black/5 rounded-lg"
|
||||
className="group relative mr-1 rounded-lg border-[0.5px] border-black/5"
|
||||
>
|
||||
{item.type === TransferMethod.local_file && item.progress !== 100 && (
|
||||
<>
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center z-[1] bg-black/30"
|
||||
className="absolute inset-0 z-[1] flex items-center justify-center bg-black/30"
|
||||
style={{ left: item.progress > -1 ? `${item.progress}%` : 0 }}
|
||||
>
|
||||
{item.progress === -1 && (
|
||||
<RefreshCcw01
|
||||
className="w-5 h-5 text-white"
|
||||
className="h-5 w-5 text-white"
|
||||
onClick={() => onReUpload && onReUpload(item._id)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{item.progress > -1 && (
|
||||
<span className="absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] text-sm text-white mix-blend-lighten z-[1]">
|
||||
<span className="absolute left-[50%] top-[50%] z-[1] translate-x-[-50%] translate-y-[-50%] text-sm text-white mix-blend-lighten">
|
||||
{item.progress}%
|
||||
</span>
|
||||
)}
|
||||
@@ -76,27 +76,27 @@ const ImageList: FC<ImageListProps> = ({
|
||||
{item.type === TransferMethod.remote_url && item.progress !== 100 && (
|
||||
<div
|
||||
className={`
|
||||
absolute inset-0 flex items-center justify-center rounded-lg z-[1] border
|
||||
absolute inset-0 z-[1] flex items-center justify-center rounded-lg border
|
||||
${item.progress === -1
|
||||
? 'bg-[#FEF0C7] border-[#DC6803]'
|
||||
: 'bg-black/[0.16] border-transparent'
|
||||
? 'border-[#DC6803] bg-[#FEF0C7]'
|
||||
: 'border-transparent bg-black/[0.16]'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{item.progress > -1 && (
|
||||
<RiLoader2Line className="animate-spin w-5 h-5 text-white" />
|
||||
<RiLoader2Line className="h-5 w-5 animate-spin text-white" />
|
||||
)}
|
||||
{item.progress === -1 && (
|
||||
<Tooltip
|
||||
popupContent={t('common.imageUploader.pasteImageLinkInvalid')}
|
||||
>
|
||||
<AlertTriangle className="w-4 h-4 text-[#DC6803]" />
|
||||
<AlertTriangle className="h-4 w-4 text-[#DC6803]" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<img
|
||||
className="w-16 h-16 rounded-lg object-cover cursor-pointer border-[0.5px] border-black/5"
|
||||
className="h-16 w-16 cursor-pointer rounded-lg border-[0.5px] border-black/5 object-cover"
|
||||
alt={item.file?.name}
|
||||
onLoad={() => handleImageLinkLoadSuccess(item)}
|
||||
onError={() => handleImageLinkLoadError(item)}
|
||||
@@ -118,13 +118,13 @@ const ImageList: FC<ImageListProps> = ({
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'absolute z-10 -top-[9px] -right-[9px] items-center justify-center w-[18px] h-[18px]',
|
||||
'hover:bg-state-base-hover rounded-2xl shadow-lg',
|
||||
'absolute -right-[9px] -top-[9px] z-10 h-[18px] w-[18px] items-center justify-center',
|
||||
'rounded-2xl shadow-lg hover:bg-state-base-hover',
|
||||
item.progress === -1 ? 'flex' : 'hidden group-hover:flex',
|
||||
)}
|
||||
onClick={() => onRemove && onRemove(item._id)}
|
||||
>
|
||||
<RiCloseLine className="w-3 h-3 text-text-tertiary" />
|
||||
<RiCloseLine className="h-3 w-3 text-text-tertiary" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
|
||||
interface ImagePreviewProps {
|
||||
type ImagePreviewProps = {
|
||||
url: string
|
||||
title: string
|
||||
onCancel: () => void
|
||||
@@ -61,6 +61,7 @@ const ImagePreview: FC<ImagePreviewProps> = ({
|
||||
if (url.startsWith('http') || url.startsWith('https')) {
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.target = '_blank'
|
||||
a.download = title
|
||||
a.click()
|
||||
}
|
||||
@@ -68,6 +69,7 @@ const ImagePreview: FC<ImagePreviewProps> = ({
|
||||
// Base64 image
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.target = '_blank'
|
||||
a.download = title
|
||||
a.click()
|
||||
}
|
||||
@@ -103,7 +105,7 @@ const ImagePreview: FC<ImagePreviewProps> = ({
|
||||
for (let i = 0; i < slice.length; i++)
|
||||
byteNumbers[i] = slice.charCodeAt(i)
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers)
|
||||
const byteArray = new Uint8Array(byteNumbers as any)
|
||||
byteArrays.push(byteArray)
|
||||
}
|
||||
|
||||
@@ -196,11 +198,11 @@ const ImagePreview: FC<ImagePreviewProps> = ({
|
||||
useHotkeys('esc', onCancel)
|
||||
useHotkeys('up', zoomIn)
|
||||
useHotkeys('down', zoomOut)
|
||||
useHotkeys('left', onPrev || (() => {}))
|
||||
useHotkeys('right', onNext || (() => {}))
|
||||
useHotkeys('left', onPrev || (() => { }))
|
||||
useHotkeys('right', onNext || (() => { }))
|
||||
|
||||
return createPortal(
|
||||
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000] image-preview-container'
|
||||
<div className='image-preview-container fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8'
|
||||
onClick={e => e.stopPropagation()}
|
||||
onWheel={handleWheel}
|
||||
onMouseDown={handleMouseDown}
|
||||
@@ -208,54 +210,54 @@ const ImagePreview: FC<ImagePreviewProps> = ({
|
||||
onMouseUp={handleMouseUp}
|
||||
style={{ cursor: scale > 1 ? 'move' : 'default' }}
|
||||
tabIndex={-1}>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
{ }
|
||||
<img
|
||||
ref={imgRef}
|
||||
alt={title}
|
||||
src={isBase64(url) ? `data:image/png;base64,${url}` : url}
|
||||
className='max-w-full max-h-full'
|
||||
className='max-h-full max-w-full'
|
||||
style={{
|
||||
transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
|
||||
transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
|
||||
}}
|
||||
/>
|
||||
<Tooltip popupContent={t('common.operation.copyImage')}>
|
||||
<div className='absolute top-6 right-48 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
|
||||
<div className='absolute right-48 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
|
||||
onClick={imageCopy}>
|
||||
{isCopied
|
||||
? <RiFileCopyLine className='w-4 h-4 text-green-500'/>
|
||||
: <RiFileCopyLine className='w-4 h-4 text-gray-500'/>}
|
||||
? <RiFileCopyLine className='h-4 w-4 text-green-500' />
|
||||
: <RiFileCopyLine className='h-4 w-4 text-gray-500' />}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip popupContent={t('common.operation.zoomOut')}>
|
||||
<div className='absolute top-6 right-40 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
|
||||
<div className='absolute right-40 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
|
||||
onClick={zoomOut}>
|
||||
<RiZoomOutLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiZoomOutLine className='h-4 w-4 text-gray-500' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip popupContent={t('common.operation.zoomIn')}>
|
||||
<div className='absolute top-6 right-32 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
|
||||
<div className='absolute right-32 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
|
||||
onClick={zoomIn}>
|
||||
<RiZoomInLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiZoomInLine className='h-4 w-4 text-gray-500' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip popupContent={t('common.operation.download')}>
|
||||
<div className='absolute top-6 right-24 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
|
||||
<div className='absolute right-24 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
|
||||
onClick={downloadImage}>
|
||||
<RiDownloadCloud2Line className='w-4 h-4 text-gray-500'/>
|
||||
<RiDownloadCloud2Line className='h-4 w-4 text-gray-500' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip popupContent={t('common.operation.openInNewTab')}>
|
||||
<div className='absolute top-6 right-16 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
|
||||
<div className='absolute right-16 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
|
||||
onClick={openInNewTab}>
|
||||
<RiAddBoxLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiAddBoxLine className='h-4 w-4 text-gray-500' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip popupContent={t('common.operation.cancel')}>
|
||||
<div
|
||||
className='absolute top-6 right-6 flex items-center justify-center w-8 h-8 bg-white/8 rounded-lg backdrop-blur-[2px] cursor-pointer'
|
||||
className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/8 backdrop-blur-[2px]'
|
||||
onClick={onCancel}>
|
||||
<RiCloseLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiCloseLine className='h-4 w-4 text-gray-500' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>,
|
||||
|
||||
@@ -50,15 +50,15 @@ const PasteImageLinkButton: FC<PasteImageLinkButtonProps> = ({
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleToggle}>
|
||||
<div className={`
|
||||
relative flex items-center justify-center px-3 h-8 bg-components-button-tertiary-bg hover:bg-components-button-tertiary-bg-hover text-xs text-text-tertiary rounded-lg
|
||||
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
|
||||
${disabled ? 'cursor-not-allowed' : 'cursor-pointer'}
|
||||
`}>
|
||||
<Link03 className='mr-2 w-4 h-4' />
|
||||
<Link03 className='mr-2 h-4 w-4' />
|
||||
{t('common.imageUploader.pasteImageLink')}
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<div className='p-2 w-[320px] bg-components-panel-bg border-[0.5px] border-components-panel-border rounded-lg shadow-lg'>
|
||||
<div className='w-[320px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-2 shadow-lg'>
|
||||
<ImageLinkInput onUpload={handleUpload} />
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
@@ -98,11 +98,11 @@ const TextGenerationImageUploader: FC<TextGenerationImageUploaderProps> = ({
|
||||
{
|
||||
hovering => (
|
||||
<div className={`
|
||||
flex items-center justify-center px-3 h-8 bg-components-button-tertiary-bg
|
||||
text-xs text-text-tertiary rounded-lg cursor-pointer
|
||||
flex h-8 cursor-pointer items-center justify-center rounded-lg
|
||||
bg-components-button-tertiary-bg px-3 text-xs text-text-tertiary
|
||||
${hovering && 'hover:bg-components-button-tertiary-bg-hover'}
|
||||
`}>
|
||||
<ImagePlus className='mr-2 w-4 h-4' />
|
||||
<ImagePlus className='mr-2 h-4 w-4' />
|
||||
{t('common.imageUploader.uploadFromComputer')}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { ImageFile } from '@/types/app'
|
||||
import { ALLOW_FILE_EXTENSIONS } from '@/types/app'
|
||||
|
||||
type UploaderProps = {
|
||||
children: (hovering: boolean) => JSX.Element
|
||||
children: (hovering: boolean) => React.JSX.Element
|
||||
onUpload: (imageFile: ImageFile) => void
|
||||
closePopover?: () => void
|
||||
limit?: number
|
||||
@@ -44,7 +44,7 @@ const Uploader: FC<UploaderProps> = ({
|
||||
>
|
||||
{children(hovering)}
|
||||
<input
|
||||
className='absolute block inset-0 opacity-0 text-[0] w-full disabled:cursor-not-allowed cursor-pointer'
|
||||
className='absolute inset-0 block w-full cursor-pointer text-[0] opacity-0 disabled:cursor-not-allowed'
|
||||
onClick={e => ((e.target as HTMLInputElement).value = '')}
|
||||
type='file'
|
||||
accept={ALLOW_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',')}
|
||||
|
||||
@@ -13,24 +13,23 @@ const VideoPreview: FC<VideoPreviewProps> = ({
|
||||
onCancel,
|
||||
}) => {
|
||||
return createPortal(
|
||||
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}>
|
||||
<div className='fixed inset-0 z-[1000] flex items-center justify-center bg-black/80 p-8' onClick={e => e.stopPropagation()}>
|
||||
<div>
|
||||
<video controls title={title} autoPlay={false} preload="metadata">
|
||||
<source
|
||||
type="video/mp4"
|
||||
src={url}
|
||||
className='max-w-full max-h-full'
|
||||
className='max-h-full max-w-full'
|
||||
/>
|
||||
</video>
|
||||
</div>
|
||||
<div
|
||||
className='absolute top-6 right-6 flex items-center justify-center w-8 h-8 bg-white/[0.08] rounded-lg backdrop-blur-[2px] cursor-pointer'
|
||||
className='absolute right-6 top-6 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-white/[0.08] backdrop-blur-[2px]'
|
||||
onClick={onCancel}
|
||||
>
|
||||
<RiCloseLine className='w-4 h-4 text-gray-500'/>
|
||||
<RiCloseLine className='h-4 w-4 text-gray-500'/>
|
||||
</div>
|
||||
</div>
|
||||
,
|
||||
</div>,
|
||||
document.body,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user