FileItem.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. const html = require('yo-yo')
  2. const { getETA,
  3. getSpeed,
  4. prettyETA,
  5. getFileNameAndExtension,
  6. truncateString,
  7. copyToClipboard } = require('../../core/Utils')
  8. const prettyBytes = require('prettier-bytes')
  9. const FileItemProgress = require('./FileItemProgress')
  10. const getFileTypeIcon = require('./getFileTypeIcon')
  11. const { iconEdit, iconCopy, iconRetry } = require('./icons')
  12. module.exports = function fileItem (props) {
  13. const file = props.file
  14. const acquirers = props.acquirers
  15. const isProcessing = file.progress.preprocess || file.progress.postprocess
  16. const isUploaded = file.progress.uploadComplete && !isProcessing && !file.error
  17. const uploadInProgressOrComplete = file.progress.uploadStarted || isProcessing
  18. const uploadInProgress = (file.progress.uploadStarted && !file.progress.uploadComplete) || isProcessing
  19. const isPaused = file.isPaused || false
  20. const error = file.error || false
  21. const fileName = getFileNameAndExtension(file.meta.name).name
  22. const truncatedFileName = props.isWide ? truncateString(fileName, 16) : fileName
  23. const onPauseResumeCancelRetry = (ev) => {
  24. if (isUploaded) return
  25. if (error) {
  26. props.retryUpload(file.id)
  27. return
  28. }
  29. if (props.resumableUploads) {
  30. props.pauseUpload(file.id)
  31. } else {
  32. props.cancelUpload(file.id)
  33. }
  34. }
  35. return html`<li class="UppyDashboardItem
  36. ${uploadInProgress ? 'is-inprogress' : ''}
  37. ${isProcessing ? 'is-processing' : ''}
  38. ${isUploaded ? 'is-complete' : ''}
  39. ${isPaused ? 'is-paused' : ''}
  40. ${error ? 'is-error' : ''}
  41. ${props.resumableUploads ? 'is-resumable' : ''}"
  42. id="uppy_${file.id}"
  43. title="${file.meta.name}">
  44. <div class="UppyDashboardItem-preview">
  45. <div class="UppyDashboardItem-previewInnerWrap" style="background-color: ${getFileTypeIcon(file.type).color}">
  46. ${file.preview
  47. ? html`<img alt="${file.name}" src="${file.preview}">`
  48. : html`<div class="UppyDashboardItem-previewIconWrap">
  49. <span class="UppyDashboardItem-previewIcon" style="color: ${getFileTypeIcon(file.type).color}">${getFileTypeIcon(file.type).icon}</span>
  50. <svg class="UppyDashboardItem-previewIconBg" width="72" height="93" viewBox="0 0 72 93"><g><path d="M24.08 5h38.922A2.997 2.997 0 0 1 66 8.003v74.994A2.997 2.997 0 0 1 63.004 86H8.996A2.998 2.998 0 0 1 6 83.01V22.234L24.08 5z" fill="#FFF"/><path d="M24 5L6 22.248h15.007A2.995 2.995 0 0 0 24 19.244V5z" fill="#E4E4E4"/></g></svg>
  51. </div>`
  52. }
  53. </div>
  54. <div class="UppyDashboardItem-progress">
  55. ${isUploaded
  56. ? html`<div class="UppyDashboardItem-progressIndicator">
  57. ${FileItemProgress({
  58. progress: file.progress.percentage,
  59. fileID: file.id
  60. })}
  61. </div>`
  62. : html`<button class="UppyDashboardItem-progressIndicator"
  63. type="button"
  64. title="${isUploaded
  65. ? 'upload complete'
  66. : props.resumableUploads
  67. ? file.isPaused
  68. ? 'resume upload'
  69. : 'pause upload'
  70. : 'cancel upload'
  71. }"
  72. onclick=${onPauseResumeCancelRetry}>
  73. ${error
  74. ? iconRetry()
  75. : FileItemProgress({
  76. progress: file.progress.percentage,
  77. fileID: file.id
  78. })
  79. }
  80. </button>`
  81. }
  82. ${props.showProgressDetails
  83. ? html`<div class="UppyDashboardItem-progressInfo"
  84. title="${props.i18n('fileProgress')}"
  85. aria-label="${props.i18n('fileProgress')}">
  86. ${!file.isPaused && !isUploaded
  87. ? html`<span>${prettyETA(getETA(file.progress))} ・ ↑ ${prettyBytes(getSpeed(file.progress))}/s</span>`
  88. : null
  89. }
  90. </div>`
  91. : null
  92. }
  93. </div>
  94. </div>
  95. <div class="UppyDashboardItem-info">
  96. <h4 class="UppyDashboardItem-name" title="${fileName}">
  97. ${file.uploadURL
  98. ? html`<a href="${file.uploadURL}" target="_blank">
  99. ${file.extension ? truncatedFileName + '.' + file.extension : truncatedFileName}
  100. </a>`
  101. : file.extension ? truncatedFileName + '.' + file.extension : truncatedFileName
  102. }
  103. </h4>
  104. <div class="UppyDashboardItem-status">
  105. ${file.data.size && html`<div class="UppyDashboardItem-statusSize">${prettyBytes(file.data.size)}</div>`}
  106. ${file.source && html`<div class="UppyDashboardItem-sourceIcon">
  107. ${acquirers.map(acquirer => {
  108. if (acquirer.id === file.source) return html`<span title="${props.i18n('fileSource')}: ${acquirer.name}">${acquirer.icon()}</span>`
  109. })}
  110. </div>`
  111. }
  112. </div>
  113. ${!uploadInProgressOrComplete
  114. ? html`<button class="UppyDashboardItem-edit"
  115. type="button"
  116. aria-label="Edit file"
  117. title="Edit file"
  118. onclick=${(e) => props.showFileCard(file.id)}>
  119. ${iconEdit()}</button>`
  120. : null
  121. }
  122. ${file.uploadURL
  123. ? html`<button class="UppyDashboardItem-copyLink"
  124. type="button"
  125. aria-label="Copy link"
  126. title="Copy link"
  127. onclick=${() => {
  128. copyToClipboard(file.uploadURL, props.i18n('copyLinkToClipboardFallback'))
  129. .then(() => {
  130. props.log('Link copied to clipboard.')
  131. props.info(props.i18n('copyLinkToClipboardSuccess'), 'info', 3000)
  132. })
  133. .catch(props.log)
  134. }}>${iconCopy()}</button>`
  135. : null
  136. }
  137. </div>
  138. <div class="UppyDashboardItem-action">
  139. ${!isUploaded
  140. ? html`<button class="UppyDashboardItem-remove"
  141. type="button"
  142. aria-label="Remove file"
  143. title="Remove file"
  144. onclick=${() => props.removeFile(file.id)}>
  145. <svg aria-hidden="true" class="UppyIcon" width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
  146. <path stroke="#FFF" stroke-width="0.8px" fill-rule="nonzero" vector-effect="non-scaling-stroke" d="M30 1C14 1 1 14 1 30s13 29 29 29 29-13 29-29S46 1 30 1z" />
  147. <path fill="#FFF" vector-effect="non-scaling-stroke" d="M42 39.667L39.667 42 30 32.333 20.333 42 18 39.667 27.667 30 18 20.333 20.333 18 30 27.667 39.667 18 42 20.333 32.333 30z"/>
  148. </svg>
  149. </button>`
  150. : null
  151. }
  152. </div>
  153. </li>`
  154. }