file uploader

This commit is contained in:
StyleZhang 2024-08-13 15:24:09 +08:00
parent 57f178902f
commit d7c8bced9b
7 changed files with 95 additions and 79 deletions

View File

@ -16,7 +16,8 @@ import type { Theme } from '../../embedded-chatbot/theme/theme-context'
import { useTextAreaHeight } from './hooks' import { useTextAreaHeight } from './hooks'
import Operation from './operation' import Operation from './operation'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
// import { FileListFlexOperation } from '@/app/components/base/file-uploader' import { FileListFlexOperation } from '@/app/components/base/file-uploader'
import { FileContextProvider } from '@/app/components/base/file-uploader/store'
import VoiceInput from '@/app/components/base/voice-input' import VoiceInput from '@/app/components/base/voice-input'
import { useToastContext } from '@/app/components/base/toast' import { useToastContext } from '@/app/components/base/toast'
@ -92,58 +93,60 @@ const ChatInputArea = ({
) )
return ( return (
<div <FileContextProvider>
className={cn( <div
'py-[9px] bg-components-panel-bg-blur border border-components-chat-input-border rounded-xl shadow-md', className={cn(
)} 'py-[9px] bg-components-panel-bg-blur border border-components-chat-input-border rounded-xl shadow-md',
> )}
<div className='relative px-[9px] max-h-[158px] overflow-x-hidden overflow-y-auto'> >
{/* <FileListFlexOperation /> */} <div className='relative px-[9px] max-h-[158px] overflow-x-hidden overflow-y-auto'>
<div <FileListFlexOperation />
ref={wrapperRef} <div
className='flex items-center justify-between' ref={wrapperRef}
> className='flex items-center justify-between'
<div className='flex items-center relative grow w-full'> >
<div <div className='flex items-center relative grow w-full'>
ref={textValueRef} <div
className='absolute w-auto h-auto p-1 leading-6 body-lg-regular pointer-events-none whitespace-pre invisible' ref={textValueRef}
> className='absolute w-auto h-auto p-1 leading-6 body-lg-regular pointer-events-none whitespace-pre invisible'
{query} >
{query}
</div>
<Textarea
ref={textareaRef}
className='p-1 w-full leading-6 body-lg-regular text-text-tertiary outline-none'
placeholder='Enter message...'
autoSize={{ minRows: 1 }}
onResize={handleTextareaResize}
value={query}
onChange={(e) => {
setQuery(e.target.value)
handleTextareaResize()
}}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
/>
</div> </div>
<Textarea {
ref={textareaRef} !isMultipleLine && operation
className='p-1 w-full leading-6 body-lg-regular text-text-tertiary outline-none' }
placeholder='Enter message...'
autoSize={{ minRows: 1 }}
onResize={handleTextareaResize}
value={query}
onChange={(e) => {
setQuery(e.target.value)
handleTextareaResize()
}}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
/>
</div> </div>
{ {
!isMultipleLine && operation showVoiceInput && (
<VoiceInput
onCancel={() => setShowVoiceInput(false)}
onConverted={text => setQuery(text)}
/>
)
} }
</div> </div>
{ {
showVoiceInput && ( isMultipleLine && (
<VoiceInput <div className='px-[9px]'>{operation}</div>
onCancel={() => setShowVoiceInput(false)}
onConverted={text => setQuery(text)}
/>
) )
} }
</div> </div>
{ </FileContextProvider>
isMultipleLine && (
<div className='px-[9px]'>{operation}</div>
)
}
</div>
) )
} }

View File

@ -8,7 +8,7 @@ type FileListItemProps = {
isFile?: boolean isFile?: boolean
className?: string className?: string
} }
const FileListItem = ({ const FileListFlexItem = ({
isFile, isFile,
className, className,
}: FileListItemProps) => { }: FileListItemProps) => {
@ -48,4 +48,4 @@ const FileListItem = ({
) )
} }
export default memo(FileListItem) export default memo(FileListFlexItem)

View File

@ -3,33 +3,31 @@ import {
memo, memo,
} from 'react' } from 'react'
import { RiCloseLine } from '@remixicon/react' import { RiCloseLine } from '@remixicon/react'
import FileListItem from './file-list-item' import { useStore } from '../store'
import FileListItem from './file-list-flex-item'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
const FileListFlexOperation = forwardRef<HTMLDivElement>((_, ref) => { const FileListFlexOperation = forwardRef<HTMLDivElement>((_, ref) => {
const files = useStore(s => s.files)
return ( return (
<div <div
ref={ref} ref={ref}
className='flex flex-wrap gap-2' className='flex flex-wrap gap-2'
> >
<div className='relative'> {
<Button className='absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full'> files.map(file => (
<RiCloseLine className='w-4 h-4 text-components-button-secondary-text' /> <div
</Button> key={file._id}
<FileListItem /> className='relative'
</div> >
<div className='relative'> <Button className='absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full'>
<Button className='absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full'> <RiCloseLine className='w-4 h-4 text-components-button-secondary-text' />
<RiCloseLine className='w-4 h-4 text-components-button-secondary-text' /> </Button>
</Button> <FileListItem />
<FileListItem /> </div>
</div> ))
<div className='relative'> }
<Button className='absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full'>
<RiCloseLine className='w-4 h-4 text-components-button-secondary-text' />
</Button>
<FileListItem isFile />
</div>
</div> </div>
) )
}) })

View File

@ -2,7 +2,7 @@ import {
forwardRef, forwardRef,
memo, memo,
} from 'react' } from 'react'
import FileListItem from './file-list-item' import FileListFlexItem from './file-list-flex-item'
const FileListFlexPreview = forwardRef<HTMLDivElement>((_, ref) => { const FileListFlexPreview = forwardRef<HTMLDivElement>((_, ref) => {
return ( return (
@ -10,10 +10,10 @@ const FileListFlexPreview = forwardRef<HTMLDivElement>((_, ref) => {
ref={ref} ref={ref}
className='flex flex-wrap gap-2' className='flex flex-wrap gap-2'
> >
<FileListItem /> <FileListFlexItem />
<FileListItem /> <FileListFlexItem />
<FileListItem isFile /> <FileListFlexItem isFile />
<FileListItem isFile /> <FileListFlexItem isFile />
</div> </div>
) )
}) })

View File

@ -1,5 +1,4 @@
import { import {
memo,
useCallback, useCallback,
} from 'react' } from 'react'
import { import {
@ -8,6 +7,10 @@ import {
} from '@remixicon/react' } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import FileFromLinkOrLocal from '../file-from-link-or-local' import FileFromLinkOrLocal from '../file-from-link-or-local'
import {
FileContextProvider,
useStore,
} from '../store'
import FileInAttachmentItem from './file-in-attachment-item' import FileInAttachmentItem from './file-in-attachment-item'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
@ -19,6 +22,7 @@ type Option = {
} }
const FileUploaderInAttachment = () => { const FileUploaderInAttachment = () => {
const { t } = useTranslation() const { t } = useTranslation()
const files = useStore(s => s.files)
const options = [ const options = [
{ {
value: 'local', value: 'local',
@ -68,11 +72,24 @@ const FileUploaderInAttachment = () => {
{options.map(renderOption)} {options.map(renderOption)}
</div> </div>
<div className='mt-1 space-y-1'> <div className='mt-1 space-y-1'>
<FileInAttachmentItem /> {
<FileInAttachmentItem /> files.map(file => (
<FileInAttachmentItem
key={file._id}
/>
))
}
</div> </div>
</div> </div>
) )
} }
export default memo(FileUploaderInAttachment) const FileUploaderInAttachmentWrapper = () => {
return (
<FileContextProvider>
<FileUploaderInAttachment />
</FileContextProvider>
)
}
export default FileUploaderInAttachmentWrapper

View File

@ -1,4 +1,4 @@
export { default as FileUploaderInAttachment } from './file-uploader-in-attachment' export { default as FileUploaderInAttachmentWrapper } from './file-uploader-in-attachment'
export { default as FileUploaderInChatInput } from './file-uploader-in-chat-input' export { default as FileUploaderInChatInput } from './file-uploader-in-chat-input'
export { default as FileTypeIcon } from './file-type-icon' export { default as FileTypeIcon } from './file-type-icon'
export { default as FileListFlexOperation } from './file-list-flex/file-list-flex-operation' export { default as FileListFlexOperation } from './file-list-flex/file-list-flex-operation'

View File

@ -12,8 +12,7 @@ import Textarea from '@/app/components/base/textarea'
import { DEFAULT_VALUE_MAX_LEN } from '@/config' import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader' import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
import type { VisionFile, VisionSettings } from '@/types/app' import type { VisionFile, VisionSettings } from '@/types/app'
import ChatInputArea from '@/app/components/base/chat/chat/chat-input-area' import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
import { FileUploaderInAttachment } from '@/app/components/base/file-uploader'
export type IRunOnceProps = { export type IRunOnceProps = {
siteInfo: SiteInfo siteInfo: SiteInfo
@ -115,8 +114,7 @@ const RunOnce: FC<IRunOnceProps> = ({
</div> </div>
) )
} }
<ChatInputArea /> <FileUploaderInAttachmentWrapper />
<FileUploaderInAttachment />
{promptConfig.prompt_variables.length > 0 && ( {promptConfig.prompt_variables.length > 0 && (
<div className='mt-4 h-[1px] bg-gray-100'></div> <div className='mt-4 h-[1px] bg-gray-100'></div>
)} )}