You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

file-item.tsx 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import {
  2. RiCloseLine,
  3. RiDownloadLine,
  4. } from '@remixicon/react'
  5. import {
  6. getFileAppearanceType,
  7. getFileExtension,
  8. } from '../utils'
  9. import FileTypeIcon from '../file-type-icon'
  10. import type { FileEntity } from '../types'
  11. import cn from '@/utils/classnames'
  12. import { formatFileSize } from '@/utils/format'
  13. import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
  14. import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
  15. import ActionButton from '@/app/components/base/action-button'
  16. import Button from '@/app/components/base/button'
  17. type FileItemProps = {
  18. file: FileEntity
  19. showDeleteAction?: boolean
  20. showDownloadAction?: boolean
  21. onRemove?: (fileId: string) => void
  22. onReUpload?: (fileId: string) => void
  23. }
  24. const FileItem = ({
  25. file,
  26. showDeleteAction,
  27. showDownloadAction = true,
  28. onRemove,
  29. onReUpload,
  30. }: FileItemProps) => {
  31. const { id, name, type, progress } = file
  32. const ext = getFileExtension(name, type)
  33. const uploadError = progress === -1
  34. return (
  35. <div
  36. className={cn(
  37. 'group relative p-2 w-[144px] h-[68px] rounded-lg border-[0.5px] border-components-panel-border bg-components-card-bg shadow-xs',
  38. !uploadError && 'hover:bg-components-card-bg-alt',
  39. uploadError && 'border border-state-destructive-border bg-state-destructive-hover',
  40. uploadError && 'hover:border-[0.5px] hover:border-state-destructive-border bg-state-destructive-hover-alt',
  41. )}
  42. >
  43. {
  44. showDeleteAction && (
  45. <Button
  46. className='hidden group-hover:flex absolute -right-1.5 -top-1.5 p-0 w-5 h-5 rounded-full z-10'
  47. onClick={() => onRemove?.(id)}
  48. >
  49. <RiCloseLine className='w-4 h-4 text-components-button-secondary-text' />
  50. </Button>
  51. )
  52. }
  53. <div className='mb-1 h-8 line-clamp-2 system-xs-medium text-text-tertiary'>
  54. {name}
  55. </div>
  56. <div className='flex items-center justify-between'>
  57. <div className='flex items-center system-2xs-medium-uppercase text-text-tertiary'>
  58. <FileTypeIcon
  59. size='sm'
  60. type={getFileAppearanceType(name, type)}
  61. className='mr-1'
  62. />
  63. {
  64. ext && (
  65. <>
  66. {ext}
  67. <div className='mx-1'>·</div>
  68. </>
  69. )
  70. }
  71. {formatFileSize(file.size || 0)}
  72. </div>
  73. {
  74. showDownloadAction && (
  75. <ActionButton
  76. size='xs'
  77. >
  78. <RiDownloadLine className='w-3.5 h-3.5 text-text-tertiary' />
  79. </ActionButton>
  80. )
  81. }
  82. {
  83. progress > 0 && progress < 100 && (
  84. <ProgressCircle
  85. percentage={progress}
  86. size={12}
  87. />
  88. )
  89. }
  90. {
  91. uploadError && (
  92. <ReplayLine
  93. className='w-4 h-4 text-text-tertiary'
  94. onClick={() => onReUpload?.(id)}
  95. />
  96. )
  97. }
  98. </div>
  99. </div>
  100. )
  101. }
  102. export default FileItem