22 RiCloseLine ,
33 RiDownloadLine ,
44} from '@remixicon/react'
5+ import { useState } from 'react'
56import {
67 downloadFile ,
78 fileIsUploaded ,
@@ -16,11 +17,15 @@ import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
1617import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
1718import ActionButton from '@/app/components/base/action-button'
1819import Button from '@/app/components/base/button'
20+ import PdfPreview from '@/app/components/base/file-uploader/pdf-preview'
21+ import AudioPreview from '@/app/components/base/file-uploader/audio-preview'
22+ import VideoPreview from '@/app/components/base/file-uploader/video-preview'
1923
2024type FileItemProps = {
2125 file : FileEntity
2226 showDeleteAction ?: boolean
2327 showDownloadAction ?: boolean
28+ canPreview ?: boolean
2429 onRemove ?: ( fileId : string ) => void
2530 onReUpload ?: ( fileId : string ) => void
2631}
@@ -30,88 +35,120 @@ const FileItem = ({
3035 showDownloadAction = true ,
3136 onRemove,
3237 onReUpload,
38+ canPreview,
3339} : FileItemProps ) => {
3440 const { id, name, type, progress, url, base64Url, isRemote } = file
41+ const [ previewUrl , setPreviewUrl ] = useState ( '' )
3542 const ext = getFileExtension ( name , type , isRemote )
3643 const uploadError = progress === - 1
3744
45+ let tmp_preview_url = url || base64Url
46+ if ( ! tmp_preview_url && file ?. originalFile )
47+ tmp_preview_url = URL . createObjectURL ( file . originalFile . slice ( ) ) . toString ( )
48+
3849 return (
39- < div
40- className = { cn (
41- 'group/file-item relative p-2 w-[144px] h-[68px] rounded-lg border-[0.5px] border-components-panel-border bg-components-card-bg shadow-xs' ,
42- ! uploadError && 'hover:bg-components-card-bg-alt' ,
43- uploadError && 'border border-state-destructive-border bg-state-destructive-hover' ,
44- uploadError && 'hover:border-[0.5px] hover:border-state-destructive-border bg-state-destructive-hover-alt' ,
45- ) }
46- >
47- {
48- showDeleteAction && (
49- < Button
50- className = 'hidden group-hover/file-item:flex absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full z-[11]'
51- onClick = { ( ) => onRemove ?.( id ) }
52- >
53- < RiCloseLine className = 'w-4 h-4 text-components-button-secondary-text' />
54- </ Button >
55- )
56- }
50+ < >
5751 < div
58- className = 'mb-1 h-8 line-clamp-2 system-xs-medium text-text-tertiary break-all'
59- title = { name }
52+ className = { cn (
53+ 'group/file-item relative p-2 w-[144px] h-[68px] rounded-lg border-[0.5px] border-components-panel-border bg-components-card-bg shadow-xs' ,
54+ ! uploadError && 'hover:bg-components-card-bg-alt' ,
55+ uploadError && 'border border-state-destructive-border bg-state-destructive-hover' ,
56+ uploadError && 'hover:border-[0.5px] hover:border-state-destructive-border bg-state-destructive-hover-alt' ,
57+ ) }
6058 >
61- { name }
62- </ div >
63- < div className = 'relative flex items-center justify-between' >
64- < div className = 'flex items-center system-2xs-medium-uppercase text-text-tertiary' >
65- < FileTypeIcon
66- size = 'sm'
67- type = { getFileAppearanceType ( name , type ) }
68- className = 'mr-1'
69- />
59+ {
60+ showDeleteAction && (
61+ < Button
62+ className = 'hidden group-hover/file-item:flex absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full z-[11]'
63+ onClick = { ( ) => onRemove ?.( id ) }
64+ >
65+ < RiCloseLine className = 'w-4 h-4 text-components-button-secondary-text' />
66+ </ Button >
67+ )
68+ }
69+ < div
70+ className = 'mb-1 h-8 line-clamp-2 system-xs-medium text-text-tertiary break-all cursor-pointer'
71+ title = { name }
72+ onClick = { ( ) => canPreview && setPreviewUrl ( tmp_preview_url || '' ) }
73+ >
74+ { name }
75+ </ div >
76+ < div className = 'relative flex items-center justify-between' >
77+ < div className = 'flex items-center system-2xs-medium-uppercase text-text-tertiary' >
78+ < FileTypeIcon
79+ size = 'sm'
80+ type = { getFileAppearanceType ( name , type ) }
81+ className = 'mr-1'
82+ />
83+ {
84+ ext && (
85+ < >
86+ { ext }
87+ < div className = 'mx-1' > ·</ div >
88+ </ >
89+ )
90+ }
91+ {
92+ ! ! file . size && formatFileSize ( file . size )
93+ }
94+ </ div >
95+ {
96+ showDownloadAction && tmp_preview_url && (
97+ < ActionButton
98+ size = 'm'
99+ className = 'hidden group-hover/file-item:flex absolute -right-1 -top-1'
100+ onClick = { ( e ) => {
101+ e . stopPropagation ( )
102+ downloadFile ( tmp_preview_url || '' , name )
103+ } }
104+ >
105+ < RiDownloadLine className = 'w-3.5 h-3.5 text-text-tertiary' />
106+ </ ActionButton >
107+ )
108+ }
70109 {
71- ext && (
72- < >
73- { ext }
74- < div className = 'mx-1' > ·</ div >
75- </ >
110+ progress >= 0 && ! fileIsUploaded ( file ) && (
111+ < ProgressCircle
112+ percentage = { progress }
113+ size = { 12 }
114+ className = 'shrink-0'
115+ />
76116 )
77117 }
78118 {
79- ! ! file . size && formatFileSize ( file . size )
119+ uploadError && (
120+ < ReplayLine
121+ className = 'w-4 h-4 text-text-tertiary'
122+ onClick = { ( ) => onReUpload ?.( id ) }
123+ />
124+ )
80125 }
81126 </ div >
82- {
83- showDownloadAction && url && (
84- < ActionButton
85- size = 'm'
86- className = 'hidden group-hover/file-item:flex absolute -right-1 -top-1'
87- onClick = { ( e ) => {
88- e . stopPropagation ( )
89- downloadFile ( url || base64Url || '' , name )
90- } }
91- >
92- < RiDownloadLine className = 'w-3.5 h-3.5 text-text-tertiary' />
93- </ ActionButton >
94- )
95- }
96- {
97- progress >= 0 && ! fileIsUploaded ( file ) && (
98- < ProgressCircle
99- percentage = { progress }
100- size = { 12 }
101- className = 'shrink-0'
102- />
103- )
104- }
105- {
106- uploadError && (
107- < ReplayLine
108- className = 'w-4 h-4 text-text-tertiary'
109- onClick = { ( ) => onReUpload ?.( id ) }
110- />
111- )
112- }
113127 </ div >
114- </ div >
128+ {
129+ type . split ( '/' ) [ 0 ] === 'audio' && canPreview && previewUrl && (
130+ < AudioPreview
131+ title = { name }
132+ url = { previewUrl }
133+ onCancel = { ( ) => setPreviewUrl ( '' ) }
134+ />
135+ )
136+ }
137+ {
138+ type . split ( '/' ) [ 0 ] === 'video' && canPreview && previewUrl && (
139+ < VideoPreview
140+ title = { name }
141+ url = { previewUrl }
142+ onCancel = { ( ) => setPreviewUrl ( '' ) }
143+ />
144+ )
145+ }
146+ {
147+ type . split ( '/' ) [ 1 ] === 'pdf' && canPreview && previewUrl && (
148+ < PdfPreview url = { previewUrl } onCancel = { ( ) => { setPreviewUrl ( '' ) } } />
149+ )
150+ }
151+ </ >
115152 )
116153}
117154
0 commit comments