فهرست منبع

Editor component, сanEditFile() and conditional “edit file” button, based on

Artur Paikin 4 سال پیش
والد
کامیت
916d7cb320

+ 3 - 3
packages/@uppy/dashboard/src/components/Dashboard.js

@@ -119,7 +119,7 @@ module.exports = function Dashboard (props) {
           )}
           )}
 
 
           <TransitionWrapper>
           <TransitionWrapper>
-            {props.showAddFilesPanel ? <AddFilesPanel key="AddFilesPanel" {...props} isSizeMD={isSizeMD} /> : null}
+            {props.showAddFilesPanel ? <AddFilesPanel key="AddFiles" {...props} isSizeMD={isSizeMD} /> : null}
           </TransitionWrapper>
           </TransitionWrapper>
 
 
           <TransitionWrapper>
           <TransitionWrapper>
@@ -127,11 +127,11 @@ module.exports = function Dashboard (props) {
           </TransitionWrapper>
           </TransitionWrapper>
 
 
           <TransitionWrapper>
           <TransitionWrapper>
-            {props.activePickerPanel ? <PickerPanelContent key="PickerPanelContent" {...props} /> : null}
+            {props.activePickerPanel ? <PickerPanelContent key="Picker" {...props} /> : null}
           </TransitionWrapper>
           </TransitionWrapper>
 
 
           <TransitionWrapper>
           <TransitionWrapper>
-            {props.showFileEditor ? <EditorPanel key="EditorPanel" {...props} /> : null}
+            {props.showFileEditor ? <EditorPanel key="Editor" {...props} /> : null}
           </TransitionWrapper>
           </TransitionWrapper>
 
 
           <div class="uppy-Dashboard-progressindicators">
           <div class="uppy-Dashboard-progressindicators">

+ 3 - 2
packages/@uppy/dashboard/src/components/EditorPanel.js

@@ -7,7 +7,7 @@ function EditorPanel (props) {
     <div
     <div
       class="uppy-DashboardContent-panel"
       class="uppy-DashboardContent-panel"
       role="tabpanel"
       role="tabpanel"
-      data-uppy-panelType="PickerPanel"
+      data-uppy-panelType="FileEditor"
       id="uppy-DashboardContent-panel--editor"
       id="uppy-DashboardContent-panel--editor"
     >
     >
       <div class="uppy-DashboardContent-bar">
       <div class="uppy-DashboardContent-bar">
@@ -20,7 +20,8 @@ function EditorPanel (props) {
           class="uppy-DashboardContent-back"
           class="uppy-DashboardContent-back"
           type="button"
           type="button"
           onclick={props.hideAllPanels}
           onclick={props.hideAllPanels}
-        >{props.i18n('done')}
+        >
+          {props.i18n('done')}
         </button>
         </button>
       </div>
       </div>
       <div class="uppy-DashboardContent-panelBody">
       <div class="uppy-DashboardContent-panelBody">

+ 14 - 11
packages/@uppy/dashboard/src/components/FileCard/index.js

@@ -86,6 +86,11 @@ class FileCard extends Component {
   render () {
   render () {
     const file = this.props.files[this.props.fileCardFor]
     const file = this.props.files[this.props.fileCardFor]
 
 
+    let showEditButton
+    this.props.editors.forEach((target) => {
+      showEditButton = this.props.getPlugin(target.id).сanEditFile(file)
+    })
+
     return (
     return (
       <div
       <div
         class="uppy-Dashboard-FileCard"
         class="uppy-Dashboard-FileCard"
@@ -111,17 +116,15 @@ class FileCard extends Component {
 
 
         <div class="uppy-Dashboard-FileCard-inner">
         <div class="uppy-Dashboard-FileCard-inner">
           <div class="uppy-Dashboard-FileCard-preview" style={{ backgroundColor: getFileTypeIcon(file.type).color }}>
           <div class="uppy-Dashboard-FileCard-preview" style={{ backgroundColor: getFileTypeIcon(file.type).color }}>
-            <FilePreview
-              file={file}
-              uppy={this.props.uppy}
-              openFileEditor={this.props.openFileEditor}
-            />
-            <button
-              class="uppy-u-reset uppy-c-btn"
-              onClick={() => this.props.openFileEditor(file)}
-            >
-              Edit
-            </button>
+            <FilePreview file={file} />
+            {showEditButton &&
+              <button
+                type="button"
+                class="uppy-u-reset uppy-c-btn uppy-Dashboard-FileCard-edit"
+                onClick={() => this.props.openFileEditor(file)}
+              >
+                {this.props.i18n('editFile')}
+              </button>}
           </div>
           </div>
 
 
           <div class="uppy-Dashboard-FileCard-info">
           <div class="uppy-Dashboard-FileCard-info">

+ 16 - 0
packages/@uppy/dashboard/src/components/FileCard/index.scss

@@ -49,6 +49,7 @@
       display: flex;
       display: flex;
       align-items: center;
       align-items: center;
       justify-content: center;
       justify-content: center;
+      position: relative;
 
 
       [data-uppy-theme="dark"] & {
       [data-uppy-theme="dark"] & {
         background-color: $gray-800;
         background-color: $gray-800;
@@ -68,6 +69,21 @@
       }
       }
     // ...uppy-Dashboard-FileCard-preview|
     // ...uppy-Dashboard-FileCard-preview|
 
 
+    .uppy-Dashboard-FileCard-edit {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      font-size: 13px;
+      background-color: rgba($black, 0.5);
+      color: $white;
+      padding: 7px 15px;
+      border-radius: 50px;
+
+      &:hover {
+        background-color: rgba($black, 0.8);
+      }
+    }
+
     .uppy-Dashboard-FileCard-info {
     .uppy-Dashboard-FileCard-info {
       height: 40%;
       height: 40%;
       flex-grow: 0;
       flex-grow: 0;

+ 3 - 4
packages/@uppy/dashboard/src/index.js

@@ -239,7 +239,8 @@ module.exports = class Dashboard extends Plugin {
     const { targets } = this.getPluginState()
     const { targets } = this.getPluginState()
 
 
     this.setPluginState({
     this.setPluginState({
-      showFileEditor: true
+      showFileEditor: true,
+      activeOverlayType: 'FileEditor'
     })
     })
 
 
     const editors = this._getEditors(targets)
     const editors = this._getEditors(targets)
@@ -247,9 +248,6 @@ module.exports = class Dashboard extends Plugin {
       const editorPlugin = this.uppy.getPlugin(editor.id)
       const editorPlugin = this.uppy.getPlugin(editor.id)
       editorPlugin.selectFile(file)
       editorPlugin.selectFile(file)
       setTimeout(editorPlugin.initEditor, 4)
       setTimeout(editorPlugin.initEditor, 4)
-      setTimeout(() => {
-        editorPlugin.edit()
-      }, 5000)
     })
     })
   }
   }
 
 
@@ -659,6 +657,7 @@ module.exports = class Dashboard extends Plugin {
     this.uppy.on('plugin-remove', this.removeTarget)
     this.uppy.on('plugin-remove', this.removeTarget)
     this.uppy.on('file-added', this.hideAllPanels)
     this.uppy.on('file-added', this.hideAllPanels)
     this.uppy.on('dashboard:modal-closed', this.hideAllPanels)
     this.uppy.on('dashboard:modal-closed', this.hideAllPanels)
+    this.uppy.on('file-editor:complete', this.hideAllPanels)
     this.uppy.on('complete', this.handleComplete)
     this.uppy.on('complete', this.handleComplete)
 
 
     // ___Why fire on capture?
     // ___Why fire on capture?

+ 138 - 0
packages/@uppy/image-editor/src/Editor.js

@@ -0,0 +1,138 @@
+const Cropper = require('cropperjs')
+const { h, Component } = require('preact')
+
+module.exports = class Editor extends Component {
+  componentDidMount () {
+    this.cropper = new Cropper(this.imgElement, {
+      viewMode: 1,
+      background: false,
+      autoCropArea: 1,
+      responsive: true
+    })
+  }
+
+  componentWillUnmount () {
+    this.cropper.destroy()
+  }
+
+  save = () => {
+    this.cropper.getCroppedCanvas().toBlob((blob) => {
+      this.props.save(blob)
+    }, this.props.currentImage.type, 0.8)
+  }
+
+  render () {
+    const currentImage = this.props.currentImage
+    const imageURL = URL.createObjectURL(currentImage.data)
+
+    return (
+      <div class="uppy-ImageCropper">
+        <div class="uppy-ImageCropper-container">
+          <img
+            class="uppy-ImageCropper-image"
+            alt={currentImage.name}
+            src={imageURL}
+            ref={(ref) => { this.imgElement = ref }}
+          />
+        </div>
+
+        <div class="uppy-ImageCropper-controls">
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.save()}
+          >
+            <svg class="uppy-c-icon" height="24" viewBox="0 0 24 24" width="24">
+              <path d="M0 0h24v24H0z" fill="none" />
+              <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => {
+              this.cropper.reset()
+              this.cropper.setAspectRatio(0)
+            }}
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M0 0h24v24H0z" fill="none" />
+              <path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.rotate(90)}
+            aria-label="Rotate"
+            data-microtip-position="top"
+            role="tooltip"
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M0 0h24v24H0V0zm0 0h24v24H0V0z" fill="none" />
+              <path d="M7.47 21.49C4.2 19.93 1.86 16.76 1.5 13H0c.51 6.16 5.66 11 11.95 11 .23 0 .44-.02.66-.03L8.8 20.15l-1.33 1.34zM12.05 0c-.23 0-.44.02-.66.04l3.81 3.81 1.33-1.33C19.8 4.07 22.14 7.24 22.5 11H24c-.51-6.16-5.66-11-11.95-11zM16 14h2V8c0-1.11-.9-2-2-2h-6v2h6v6zm-8 2V4H6v2H4v2h2v8c0 1.1.89 2 2 2h8v2h2v-2h2v-2H8z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.zoom(0.1)}
+          >
+            <svg class="uppy-c-icon" height="24" viewBox="0 0 24 24" width="24">
+              <path d="M0 0h24v24H0V0z" fill="none" />
+              <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
+              <path d="M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.zoom(-0.1)}
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M0 0h24v24H0V0z" fill="none" />
+              <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.setAspectRatio(1)}
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M0 0h24v24H0z" fill="none" />
+              <path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.setAspectRatio(16 / 9)}
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M 19,4.9999992 V 17.000001 H 4.9999998 V 6.9999992 H 19 m 0,-2 H 4.9999998 c -1.0999999,0 -1.9999999,0.9000001 -1.9999999,2 V 17.000001 c 0,1.1 0.9,2 1.9999999,2 H 19 c 1.1,0 2,-0.9 2,-2 V 6.9999992 c 0,-1.0999999 -0.9,-2 -2,-2 z" />
+              <path fill="none" d="M0 0h24v24H0z" />
+            </svg>
+          </button>
+
+          <button
+            type="button"
+            class="uppy-u-reset uppy-c-btn"
+            onClick={() => this.cropper.setAspectRatio(9 / 16)}
+          >
+            <svg class="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
+              <path d="M 19.000001,19 H 6.999999 V 5 h 10.000002 v 14 m 2,0 V 5 c 0,-1.0999999 -0.9,-1.9999999 -2,-1.9999999 H 6.999999 c -1.1,0 -2,0.9 -2,1.9999999 v 14 c 0,1.1 0.9,2 2,2 h 10.000002 c 1.1,0 2,-0.9 2,-2 z" />
+              <path d="M0 0h24v24H0z" fill="none" />
+            </svg>
+          </button>
+        </div>
+      </div>
+    )
+  }
+}

+ 26 - 63
packages/@uppy/image-editor/src/index.js

@@ -1,7 +1,6 @@
 const { Plugin } = require('@uppy/core')
 const { Plugin } = require('@uppy/core')
-const Cropper = require('cropperjs')
-// const Translator = require('@uppy/utils/lib/Translator')
 const { h } = require('preact')
 const { h } = require('preact')
+const Editor = require('./Editor')
 
 
 module.exports = class ImageEditor extends Plugin {
 module.exports = class ImageEditor extends Plugin {
   static VERSION = require('../package.json').version
   static VERSION = require('../package.json').version
@@ -12,74 +11,43 @@ module.exports = class ImageEditor extends Plugin {
     this.title = 'Image Editor'
     this.title = 'Image Editor'
     this.type = 'editor'
     this.type = 'editor'
 
 
-    // this.defaultLocale = {
-    //   strings: {
-    //     chooseFiles: 'Choose files'
-    //   }
-    // }
-
     // Default options
     // Default options
     const defaultOptions = {}
     const defaultOptions = {}
 
 
     // Merge default options with the ones set by user
     // Merge default options with the ones set by user
     this.opts = { ...defaultOptions, ...opts }
     this.opts = { ...defaultOptions, ...opts }
-
-    // this.i18nInit()
   }
   }
 
 
-  // setOptions (newOpts) {
-  //   super.setOptions(newOpts)
-  //   this.i18nInit()
-  // }
-
-  // i18nInit () {
-  //   this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
-  //   this.i18n = this.translator.translate.bind(this.translator)
-  //   this.i18nArray = this.translator.translateArray.bind(this.translator)
-  //   this.setPluginState() // so that UI re-renders and we see the updated locale
-  // }
+  сanEditFile (file) {
+    if (!file.type) {
+      return false
+    }
+    const fileTypeSpecific = file.type.split('/')[1]
 
 
-  edit = () => {
-    const { currentImage } = this.getPluginState()
+    if (/^(jpe?g|gif|png|bmp|webp)$/.test(fileTypeSpecific)) {
+      return true
+    }
 
 
-    this.cropper.rotate(90)
-    this.cropper.getCroppedCanvas().toBlob((blob) => {
-      this.uppy.setFileState(currentImage.id, {
-        data: blob,
-        size: blob.size,
-        preview: null
-      })
-      const updatedFile = this.uppy.getFile(currentImage.id)
-      this.uppy.emit('thumbnail:request', updatedFile)
-      this.setPluginState({
-        currentImage: updatedFile
-      })
-      this.cropper.destroy()
-    })
+    return false
   }
   }
 
 
-  initEditor = () => {
-    console.log(this.imgElement)
+  save = (blob) => {
     const { currentImage } = this.getPluginState()
     const { currentImage } = this.getPluginState()
 
 
-    if (currentImage.preview) {
-      this.cropper = new Cropper(this.imgElement, {
-        aspectRatio: 16 / 9
-        // crop (event) {
-        //   console.log(event.detail.x)
-        //   console.log(event.detail.y)
-        //   console.log(event.detail.width)
-        //   console.log(event.detail.height)
-        //   console.log(event.detail.rotate)
-        //   console.log(event.detail.scaleX)
-        //   console.log(event.detail.scaleY)
-        // }
-      })
-    }
+    this.uppy.setFileState(currentImage.id, {
+      data: blob,
+      size: blob.size,
+      preview: null
+    })
+    const updatedFile = this.uppy.getFile(currentImage.id)
+    this.uppy.emit('thumbnail:request', updatedFile)
+    this.setPluginState({
+      currentImage: updatedFile
+    })
+    this.uppy.emit('file-editor:complete', updatedFile)
   }
   }
 
 
   selectFile = (file) => {
   selectFile = (file) => {
-    console.log('set current image!', file)
     this.setPluginState({
     this.setPluginState({
       currentImage: file
       currentImage: file
     })
     })
@@ -105,17 +73,12 @@ module.exports = class ImageEditor extends Plugin {
     if (currentImage === null) {
     if (currentImage === null) {
       return
       return
     }
     }
-    const imageURL = URL.createObjectURL(currentImage.data)
 
 
     return (
     return (
-      <div class="uppy-ImageCropper">
-        <img
-          class="uppy-ImageCropper-image"
-          alt={currentImage.name}
-          src={imageURL}
-          ref={(ref) => { this.imgElement = ref }}
-        />
-      </div>
+      <Editor
+        currentImage={currentImage}
+        save={this.save}
+      />
     )
     )
   }
   }
 }
 }

+ 39 - 3
packages/@uppy/image-editor/src/style.scss

@@ -2,7 +2,43 @@
 @import '@uppy/core/src/_variables.scss';
 @import '@uppy/core/src/_variables.scss';
 @import './cropper.scss';
 @import './cropper.scss';
 
 
-.uppy-ImageCropper-image {
-  max-width: 100%;
-  max-height: 100%;
+.uppy-ImageCropper {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  height: 100%;
+}
+
+.uppy-ImageCropper-container {
+  flex-grow: 1;
+}
+
+  .uppy-ImageCropper-image {
+    display: block;
+    max-height: 400px;
+  }
+
+.uppy-ImageCropper-controls {
+  position: absolute;
+  bottom: 15px;
+  left: 50%;
+  transform: translateX(-50%);
+  background-color: rgba($black, 0.6);
+  color: $white;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.uppy-ImageCropper-controls button {
+  padding: 5px 8px;
+
+  &:hover {
+    background-color: rgba($blue, 0.8);
+  }
+
+  &:focus {
+    outline: none;
+    background-color: rgba($blue, 0.8);
+  }
 }
 }