Browse Source

Single File Mode: fix layout and make optional (#4374)

* Only enable singleFile mode when Dashboard tall enough + add centerSingleFile option

* Shorten file name when Dashboard is short 📏

* Center and flex single file, prevent overflows, contain img instead of cover

* White image background looks better

* Fix broken file type icons (shown when no image preview)

* Don't stretch images smaller than container / background

* uppy-c-textInput font-family inherit

* No shadow, retain cover when non-single-file, add paddings

* if preview is available, set white background, otherwise keep violet

* add transparency to the white background

* centerSingleFile --> singleFileFullScreen
Artur Paikin 2 years ago
parent
commit
cc5b0154c5

+ 2 - 1
packages/@uppy/core/src/_common.scss

@@ -47,9 +47,10 @@
 // Inputs
 
 .uppy-c-textInput {
-  padding: 6px 8px;
+  font-family: inherit;
   font-size: 14px;
   line-height: 1.5;
+  padding: 6px 8px;
   background-color: $white;
   border: 1px solid #ddd;
   border-radius: 4px;

+ 4 - 1
packages/@uppy/dashboard/src/Dashboard.jsx

@@ -80,6 +80,7 @@ export default class Dashboard extends UIPlugin {
       note: null,
       closeModalOnClickOutside: false,
       closeAfterFinish: false,
+      singleFileFullScreen: true,
       disableStatusBar: false,
       disableInformer: false,
       disableThumbnailGenerator: false,
@@ -422,7 +423,8 @@ export default class Dashboard extends UIPlugin {
     this.makeDashboardInsidesVisibleAnywayTimeout = setTimeout(() => {
       const pluginState = this.getPluginState()
       const isModalAndClosed = !this.opts.inline && pluginState.isHidden
-      if (
+      if (// We might want to enable this in the future
+
         // if ResizeObserver hasn't yet fired,
         !pluginState.areInsidesReadyToBeVisible
         // and it's not due to the modal being closed
@@ -1004,6 +1006,7 @@ export default class Dashboard extends UIPlugin {
       showNativePhotoCameraButton: this.opts.showNativePhotoCameraButton,
       showNativeVideoCameraButton: this.opts.showNativeVideoCameraButton,
       nativeCameraFacingMode: this.opts.nativeCameraFacingMode,
+      singleFileFullScreen: this.opts.singleFileFullScreen,
       handleCancelRestore: this.handleCancelRestore,
       handleRequestThumbnail: this.handleRequestThumbnail,
       handleCancelThumbnail: this.handleCancelThumbnail,

+ 15 - 7
packages/@uppy/dashboard/src/components/Dashboard.jsx

@@ -16,13 +16,17 @@ import Slide from './Slide.jsx'
 const WIDTH_XL = 900
 const WIDTH_LG = 700
 const WIDTH_MD = 576
-const HEIGHT_MD = 400
 
-export default function Dashboard (props) {
-  const noFiles = props.totalFileCount === 0
-  const singleFile = props.totalFileCount === 1
+const HEIGHT_MD = 330
+// We might want to enable this in the future
+// const HEIGHT_LG = 400
+// const HEIGHT_XL = 460
 
+export default function Dashboard (props) {
+  const isNoFiles = props.totalFileCount === 0
+  const isSingleFile = props.totalFileCount === 1
   const isSizeMD = props.containerWidth > WIDTH_MD
+  const isSizeHeightMD = props.containerHeight > HEIGHT_MD
 
   const dashboardClassName = classNames({
     'uppy-Dashboard': true,
@@ -35,9 +39,13 @@ export default function Dashboard (props) {
     'uppy-size--lg': props.containerWidth > WIDTH_LG,
     'uppy-size--xl': props.containerWidth > WIDTH_XL,
     'uppy-size--height-md': props.containerHeight > HEIGHT_MD,
+    // We might want to enable this in the future
+    // 'uppy-size--height-lg': props.containerHeight > HEIGHT_LG,
+    // 'uppy-size--height-xl': props.containerHeight > HEIGHT_XL,
     'uppy-Dashboard--isAddFilesPanelVisible': props.showAddFilesPanel,
     'uppy-Dashboard--isInnerWrapVisible': props.areInsidesReadyToBeVisible,
-    'uppy-Dashboard--singleFile': singleFile,
+    // Only enable “centered single file” mode when Dashboard is tall enough
+    'uppy-Dashboard--singleFile': props.singleFileFullScreen && isSingleFile && isSizeHeightMD,
   })
 
   // Important: keep these in sync with the percent width values in `src/components/FileItem/index.scss`.
@@ -50,7 +58,7 @@ export default function Dashboard (props) {
     itemsPerRow = 3
   }
 
-  const showFileList = props.showSelectedFiles && !noFiles
+  const showFileList = props.showSelectedFiles && !isNoFiles
 
   const numberOfFilesForRecovery = props.recoveredState ? Object.keys(props.recoveredState.files).length : null
   const numberOfGhosts = props.files ? Object.keys(props.files).filter((fileID) => props.files[fileID].isGhost).length : null
@@ -138,7 +146,7 @@ export default function Dashboard (props) {
             <FileList
               // eslint-disable-next-line react/jsx-props-no-spreading
               {...props}
-              singleFile={singleFile}
+              isSingleFile={isSingleFile}
               itemsPerRow={itemsPerRow}
             />
           ) : (

+ 9 - 4
packages/@uppy/dashboard/src/components/FileItem/Buttons/index.scss

@@ -30,21 +30,26 @@
     opacity: 1;
   }
 
-  .uppy-size--md &,
-  .uppy-Dashboard--singleFile & {
+  .uppy-size--md & {
     position: absolute;
     top: -8px;
+    inset-inline-end: -8px;
     z-index: $zIndex-3;
     width: 18px;
     height: 18px;
     padding: 0;
-    inset-inline-end: -8px;
 
     &:focus {
       border-radius: 50%;
     }
   }
 
+  .uppy-Dashboard--singleFile.uppy-size--height-md & {
+    position: absolute;
+    inset-inline-end: 8px;
+    top: 8px;
+  }
+
   [data-uppy-theme="dark"] & {
     color: $gray-700;
   }
@@ -55,7 +60,7 @@
 }
 
 // Only for mobile screens
-.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile) {
+.uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile.uppy-size--height-md) {
   // Vertically center Edit&Remove buttons on mobile
   .uppy-Dashboard-Item-actionWrapper {
     display: flex;

+ 2 - 2
packages/@uppy/dashboard/src/components/FileItem/FileInfo/index.jsx

@@ -7,8 +7,8 @@ const renderFileName = (props) => {
   const { author, name } = props.file.meta
 
   function getMaxNameLength () {
-    if (props.singleFile) {
-      return 200
+    if (props.isSingleFile && props.containerHeight >= 350) {
+      return 90
     }
     if (props.containerWidth <= 352) {
       return 35

+ 14 - 11
packages/@uppy/dashboard/src/components/FileItem/FilePreviewAndLink/index.jsx

@@ -4,32 +4,35 @@ import MetaErrorMessage from '../MetaErrorMessage.jsx'
 import getFileTypeIcon from '../../../utils/getFileTypeIcon.jsx'
 
 export default function FilePreviewAndLink (props) {
+  const { file, i18n, toggleFileCard, metaFields, showLinkToFileUploadResult } = props
+  const white = 'rgba(255, 255, 255, 0.5)'
+  const previewBackgroundColor = file.preview ? white : getFileTypeIcon(props.file.type).color
+
   return (
     <div
       className="uppy-Dashboard-Item-previewInnerWrap"
-      style={{ backgroundColor: getFileTypeIcon(props.file.type).color }}
+      style={{ backgroundColor: previewBackgroundColor }}
     >
       {
-        props.showLinkToFileUploadResult
-        && props.file.uploadURL
+        showLinkToFileUploadResult && file.uploadURL
           && (
           <a
             className="uppy-Dashboard-Item-previewLink"
-            href={props.file.uploadURL}
+            href={file.uploadURL}
             rel="noreferrer noopener"
             target="_blank"
-            aria-label={props.file.meta.name}
+            aria-label={file.meta.name}
           >
-            <span hidden>{props.file.meta.name}</span>
+            <span hidden>{file.meta.name}</span>
           </a>
           )
       }
-      <FilePreview file={props.file} />
+      <FilePreview file={file} />
       <MetaErrorMessage
-        file={props.file}
-        i18n={props.i18n}
-        toggleFileCard={props.toggleFileCard}
-        metaFields={props.metaFields}
+        file={file}
+        i18n={i18n}
+        toggleFileCard={toggleFileCard}
+        metaFields={metaFields}
       />
     </div>
   )

+ 13 - 0
packages/@uppy/dashboard/src/components/FileItem/FilePreviewAndLink/index.scss

@@ -14,6 +14,10 @@
   .uppy-size--md & {
     box-shadow: 0 1px 2px rgba($black, 0.15);
   }
+
+  .uppy-Dashboard--singleFile & {
+    box-shadow: none;
+  }
 }
 
 .uppy-Dashboard-Item-previewInnerWrap::after {
@@ -54,5 +58,14 @@
   // Fixes file previews being partially invisible in safari (for some pics only).
   // (https://stackoverflow.com/a/27971913/3192470)
   transform: translateZ(0);
+
+  .uppy-Dashboard--singleFile & {
+    object-fit: contain;
+    width: auto;
+    height: auto;
+    max-width: 100%;
+    max-height: 100%;
+    padding: 10px;
+  }
 }
 // ...uppy-Dashboard-Item-previewInnerWrap|

+ 2 - 1
packages/@uppy/dashboard/src/components/FileItem/index.jsx

@@ -102,11 +102,12 @@ export default class FileItem extends Component {
             id={this.props.id}
             acquirers={this.props.acquirers}
             containerWidth={this.props.containerWidth}
+            containerHeight={this.props.containerHeight}
             i18n={this.props.i18n}
             toggleAddFilesPanel={this.props.toggleAddFilesPanel}
             toggleFileCard={this.props.toggleFileCard}
             metaFields={this.props.metaFields}
-            singleFile={this.props.singleFile}
+            isSingleFile={this.props.isSingleFile}
           />
           <Buttons
             file={file}

+ 24 - 12
packages/@uppy/dashboard/src/components/FileItem/index.scss

@@ -50,14 +50,14 @@
   }
 
   .uppy-Dashboard--singleFile & {
-    display: block;
+    display: flex;
+    flex-direction: column;
     width: 100%;
     max-width: 400px;
-    height: auto;
+    height: 100%;
     border-bottom: 0;
     position: relative;
-    padding: 0;
-    margin: 10px;
+    padding: 15px;
   }
 }
 
@@ -87,6 +87,11 @@
     background-position: 50% 50%;
     background-size: 40px;
   }
+
+  .uppy-Dashboard--singleFile & {
+    background-position: 50% 50%;
+    background-size: 30%;
+  }
 }
 
 .uppy-Dashboard-Item-preview {
@@ -94,12 +99,10 @@
   position: relative;
 
   // @media only mobile
-  .uppy-Dashboard:not(.uppy-size--md):not(.uppy-Dashboard--singleFile) & {
-    flex-grow: 0;
-    flex-shrink: 0;
-    width: 50px;
-    height: 50px;
-  }
+  flex-grow: 0;
+  flex-shrink: 0;
+  width: 50px;
+  height: 50px;
 
   // @media bigger than .md
   .uppy-size--md & {
@@ -117,7 +120,12 @@
 
   .uppy-Dashboard--singleFile & {
     width: 100%;
-    height: 270px;
+    max-height: 75%;
+    flex-grow: 1;
+  }
+
+  .uppy-Dashboard--singleFile.uppy-size--md & {
+    max-height: 100%;
   }
 }
 
@@ -132,10 +140,14 @@
   .uppy-size--md &,
   .uppy-Dashboard--singleFile & {
     align-items: flex-start;
-    width: 100%;
     padding: 0;
     padding-top: 9px;
   }
+
+  .uppy-Dashboard--singleFile & {
+    width: 100%;
+    flex-grow: 0;
+  }
 }
 
 .uppy-Dashboard-Item-fileInfo {

+ 4 - 2
packages/@uppy/dashboard/src/components/FileList.jsx

@@ -46,7 +46,9 @@ export default (props) => {
     isWide: props.isWide,
     metaFields: props.metaFields,
     recoveredState: props.recoveredState,
-    singleFile: props.singleFile,
+    isSingleFile: props.isSingleFile,
+    containerWidth: props.containerWidth,
+    containerHeight: props.containerHeight,
     // callbacks
     toggleFileCard: props.toggleFileCard,
     handleRequestThumbnail: props.handleRequestThumbnail,
@@ -82,7 +84,7 @@ export default (props) => {
     </div>
   )
 
-  if (props.singleFile) {
+  if (props.isSingleFile) {
     return (
       <div class="uppy-Dashboard-files">
         {renderRow(rows[0])}

+ 6 - 3
packages/@uppy/dashboard/src/style.scss

@@ -939,8 +939,10 @@ a.uppy-Dashboard-poweredBy {
   }
 
   .uppy-Dashboard--singleFile & {
-    width: 90px;
-    height: 90px;
+    width: 100%;
+    height: 100%;
+    max-width: 60%;
+    max-height: 60%;
   }
 }
 
@@ -950,7 +952,8 @@ a.uppy-Dashboard-poweredBy {
   max-height: 75%;
 
   .uppy-Dashboard--singleFile & {
-    height: 176px;
+    width: 100%;
+    height: 100%;
   }
 }
 

+ 1 - 0
packages/@uppy/dashboard/types/index.d.ts

@@ -26,6 +26,7 @@ export interface DashboardOptions extends Options {
   animateOpenClose?: boolean
   browserBackButtonClose?: boolean
   closeAfterFinish?: boolean
+  centerSingleFile?: boolean
   closeModalOnClickOutside?: boolean
   disableInformer?: boolean
   disablePageScrollWhenModalOpen?: boolean