Browse Source

Merge pull request #29 from transloadit/dragdrop

Drag & Drop plugin, architecture
Artur Paikin 9 years ago
parent
commit
1f8496f73c

+ 3 - 3
.eslintrc

@@ -13,7 +13,7 @@
     "no-catch-shadow": 0,
     "no-class-assign": 0,
     "no-cond-assign": 2,
-    "no-console": 2,
+    "no-console": 0,
     "no-const-assign": 0,
     "no-constant-condition": 2,
     "no-continue": 0,
@@ -93,7 +93,7 @@
     "no-trailing-spaces": 0,
     "no-this-before-super": 0,
     "no-throw-literal": 0,
-    "no-undef": 2,
+    "no-undef": 0,
     "no-undef-init": 0,
     "no-undefined": 0,
     "no-unexpected-multiline": 0,
@@ -101,7 +101,7 @@
     "no-unneeded-ternary": 0,
     "no-unreachable": 2,
     "no-unused-expressions": 0,
-    "no-unused-vars": [2, {"vars": "all", "args": "after-used", "varsIgnorePattern": "css"}],
+    "no-unused-vars": [0, {"vars": "all", "args": "after-used", "varsIgnorePattern": "css"}],
     "no-use-before-define": 0,
     "no-useless-call": 0,
     "no-useless-concat": 0,

+ 1 - 0
.gitignore

@@ -2,6 +2,7 @@
 Thumbs.db
 npm-debug.log
 node_modules
+
 dist/
 lib/
 examples/playground/static/js/app.js

+ 61 - 0
bin/builder

@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Setup
+#######################################################
+transformations="[ babelify ]"
+toolpath="${1:-node_modules/.bin/browserify}"
+toolname="$(basename "${toolpath}")"
+
+if [ "${toolname}" = "node-sass" ]; then
+  srcExtension="scss"
+  dstExtension="css"
+else
+  srcExtension="js"
+  dstExtension="js"
+fi
+
+if [ "${toolname}" = "watchify" ]; then
+  extraArgs="-t ${transformations} --ignore-watch=**/build/** --verbose"
+elif [ "${toolname}" = "browserify" ]; then
+  extraArgs="-t ${transformations} --ignore-watch=**/build/** --verbose"
+else
+  extraArgs=""
+fi
+
+
+bundleTarget="build/uppy.${dstExtension}"
+
+# Individual files, built seperately
+#######################################################
+allSourceFiles=""
+for src in $(find src -name "*.${srcExtension}" -type f); do
+  allSourceFiles="${allSourceFiles} ${src}"
+  dst="build/$(basename $(dirname ${src}))/$(basename ${src})"
+  echo "--> ${src} -> ${dst}"
+
+  # Argument should be `browserify`, or `node-sass`
+  if [ "${toolname}" = "node-sass" ]; then
+    "${toolpath}" "${src}" "${dst}" ${extraArgs}
+  else
+    "${toolpath}" "${src}" -o "${dst}" ${extraArgs}
+  fi
+done
+
+# All files in one bundle
+#######################################################
+echo "--> *.${srcExtension} -> ${bundleTarget}"
+if [ "${toolname}" = "node-sass" ]; then
+  "${toolpath}" ${allSourceFiles} "${bundleTarget}" ${extraArgs}
+else
+  "${toolpath}" ${allSourceFiles} -o "${bundleTarget}" ${extraArgs}
+fi
+
+# Install into examples
+for path in $(find examples -maxdepth 1 -mindepth 1 -type d); do
+  exampleProject="$(basename "${path}")"
+  rsync \
+    -ai \
+    --exclude='.DS_Store' \
+    --exclude='.empty' \
+  build/ "examples/${exampleProject}/static/uppy"
+done

+ 14 - 4
examples/playground/index.html

@@ -26,8 +26,11 @@
   –––––––––––––––––––––––––––––––––––––––––––––––––– -->
   <link rel="icon" type="image/png" href="static/images/favicon.png">
 
+  <!-- Playground styles -->
+  <link rel="stylesheet" href="static/css/style.css">
 
-  <link rel="stylesheet" href="static/css/style.css" type="text/css" />
+  <!-- Basic Uppy styles -->
+  <link rel="stylesheet" href="static/css/uppy.css">
 </head>
 <body>
 
@@ -46,9 +49,16 @@
           and online.
         </p>
 
-        <div id="upload-target">
-          Drag & Drop here
-        </div>
+        <form id="upload-target" class="UppyDragDrop" method="post" action="/" enctype="multipart/form-data">
+            <svg class="UppyDragDrop-puppy" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125" enable-background="new 0 0 100 100"><path d="M16.582 21.3L-.085 62.713l32.94 13.295zM99.915 62.714L66.975 76.01 83.25 21.3zM50.917 68.117L62.443 56.59H37.386l11.527 11.526v5.905l-3.063 3.32 1.474 1.36 2.59-2.807 2.59 2.807 1.475-1.358-3.063-3.32zM66.976 41.415c-3.972 0-7.193-3.22-7.193-7.193 0-3.973 3.222-7.193 7.193-7.193 3.974 0 7.193 3.22 7.193 7.192 0 3.973-3.22 7.193-7.194 7.193m2.506-11.732c-.738 0-1.337.6-1.337 1.337s.6 1.336 1.337 1.336 1.337-.598 1.337-1.336-.6-1.337-1.338-1.337zM32.854 41.415c-3.973 0-7.193-3.22-7.193-7.193 0-3.973 3.22-7.193 7.194-7.193 3.973 0 7.192 3.22 7.192 7.192 0 3.973-3.22 7.193-7.192 7.193m2.506-11.732c-.738 0-1.337.6-1.337 1.337s.6 1.336 1.337 1.336 1.337-.598 1.337-1.336-.598-1.337-1.337-1.337z"/></svg>          <div>
+            <input id="UppyDragDrop-input" class="UppyDragDrop-input" type="file" name="files[]" data-multiple-caption="{count} files selected" multiple />
+            <label class="UppyDragDrop-label" for="UppyDragDrop-input"><strong>Choose a file</strong><span class="UppyDragDrop-dragText"> or drag it here</span>.</label>
+            <!-- <button class="UppyDragDrop-btn" type="submit">Upload</button> -->
+          </div>
+          <div class="UppyDragDrop-status"></div>
+        </form>
+
+        <small>Puppy icon by Jorge Fernandez del Castillo Gomez <br>from the Noun Project</small>
 
       </div>
     </div>

+ 5 - 21
examples/playground/src/js/app.js

@@ -1,24 +1,8 @@
-import Transloadit from '../../../../core';
-import { DragDrop, Tus10 } from '../../../../plugins';
+import Uppy from '../../../../src/core';
+import { DragDrop, Tus10 } from '../../../../src/plugins';
 
-const transloadit = new Transloadit({wait: false});
-const files = transloadit
-  .use(DragDrop, {modal: true, selector: '#upload-target'})
+const uppy = new Uppy({wait: false});
+const files = uppy
+  .use(DragDrop, {selector: '#upload-target'})
   .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
   .run();
-
-console.log('--> Finished transloadit. Final result: ');
-console.dir(files);
-
-// var Transloadit = require('./src/core/Transloadit.js');
-// var DragDrop = require('./src/plugins/DragDrop.js');
-// var Tus10 = require('./src/plugins/Tus10.js');
-//
-// var transloadit = new Transloadit({wait: false});
-// var files = transloadit
-//   .use(DragDrop, {modal: true})
-//   .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
-//   .run();
-//
-// console.log('--> Finished transloadit. Final result: ');
-// console.dir(files);

+ 2 - 11
examples/playground/static/css/style.css

@@ -1,12 +1,3 @@
-#upload-target {
-  width: 300px;
-  /*height: 300px;*/
-  border: 2px dashed;
-  border-color: #ccc;
-  text-align: center;
-  padding: 100px 0;
-}
-
-#upload-target.is-dragover {
-  border-color: #575757;
+.UppyDragDrop-puppy {
+  max-width: 80px;
 }

+ 44 - 1
examples/playground/static/css/uppy.css

@@ -2,4 +2,47 @@
   font-family: "Comic Sans MS";
   color: purple;
   border: 1px dashed pink;
-  font-size: 32px; }
+  font-size: 32px;
+}
+
+/**
+* Drag & Drop
+*/
+
+.UppyDragDrop {
+  width: 300px;
+  text-align: center;
+  padding: 100px 10px;
+}
+
+/* http://tympanus.net/codrops/2015/09/15/styling-customizing-file-inputs-smart-way/ */
+.UppyDragDrop-input {
+  width: 0.1px;
+	height: 0.1px;
+	opacity: 0;
+	overflow: hidden;
+	position: absolute;
+	z-index: -1;
+}
+
+.UppyDragDrop.is-dragdrop-supported {
+  border: 2px dashed;
+  border-color: #ccc;
+}
+
+.UppyDragDrop-label {
+  cursor: pointer;
+}
+
+.UppyDragDrop-dragText {
+  display: none;
+}
+
+.is-dragdrop-supported .UppyDragDrop-dragText {
+  display: inline;
+}
+
+.UppyDragDrop.is-dragover {
+  border-color: #d2ecea;
+  background-color: #dbf5f3;
+}

+ 3 - 0
package.json

@@ -45,5 +45,8 @@
     "phantomjs": "^1.9.18",
     "watchify": "^3.6.1",
     "zuul": "^3.7.2"
+  },
+  "dependencies": {
+    "async": "^1.5.0"
   }
 }

+ 47 - 21
src/core/Transloadit.js

@@ -1,3 +1,5 @@
+import async from 'async';
+
 export default class {
   constructor(opts) {
     // Dictates in what order different plugin types are ran:
@@ -10,11 +12,7 @@ export default class {
   use(Plugin, opts) {
     // Instantiate
     var plugin = new Plugin(this, opts);
-
-    // Save in plugin container
-    if (!this.plugins[plugin.type]) {
-      this.plugins[plugin.type] = [];
-    }
+    this.plugins[plugin.type] = this.plugins[plugin.type] || [];
     this.plugins[plugin.type].push(plugin);
 
     return this;
@@ -23,27 +21,55 @@ export default class {
   setProgress(plugin, percentage) {
     // Any plugin can call this via `this.core.setProgress(this, precentage)`
     console.log(plugin.type + ' plugin ' + plugin.name + ' set the progress to ' + percentage);
-
     return this;
   }
 
+  // Runs all plugins of the same type in parallel
+  runType(type, files, cb) {
+    console.dir({
+      method: 'Transloadit.runType',
+      type  : type,
+      files : files,
+      cb    : cb
+    });
+
+    const methods = [];
+    for (let p in this.plugins[type]) {
+      const plugin = this.plugins[type][p];
+      methods.push(plugin.run.bind(plugin, files));
+    }
+
+    // const methods = this.plugins[type].map(plugin => plugin.run.bind(plugin, files));
+
+    async.parallel(methods, cb);
+  }
+
+  // Runs a waterfall of runType plugin packs, like so:
+  // All preseters(data) --> All selecters(data) --> All uploaders(data) --> done
   run() {
-    // Walk over plugins in the order as defined by this.types.
-    var files = []
-    for (var j in this.types) {
-      var type = this.types[j];
-      // Walk over all plugins of this type, passing & modifying the files array as we go
-      for (var i in this.plugins[type]) {
-        var plugin = this.plugins[type][i];
-        console.log('--> Now running ' + plugin.type + ' plugin ' + plugin.name + ': ');
-        files = plugin.run(files);
-        console.dir(files);
-        console.log('');
+    console.dir({
+      method: 'Transloadit.run'
+    });
+
+    var typeMethods = [];
+    typeMethods.push(async.constant([]));
+
+    // for (let t in this.types) {
+    //   const type = this.types[t];
+    //   typeMethods.push(this.runType.bind(this, type));
+    // }
+
+    this.types.forEach(type => {
+      if (this.plugins[type]) {
+        typeMethods.push(this.runType.bind(this, type));
       }
-    }
+    });
 
-    // core.run is the final step and retuns the results (vs every other method, returning `this`)
-    // for chainability
-    return files;
+    async.waterfall(typeMethods, function (err, finalFiles) {
+      console.dir({
+        err       : err ,
+        finalFiles: finalFiles
+      });
+    });
   }
 }

+ 47 - 0
src/core/Utils.js

@@ -0,0 +1,47 @@
+// This is how we roll $('.element').toggleClass in non-jQuery world
+function toggleClass(el, className) {
+  if (el.classList) {
+    el.classList.toggle(className);
+  } else {
+    const classes = el.className.split(' ');
+    const existingIndex = classes.indexOf(className);
+
+    if (existingIndex >= 0) {
+      classes.splice(existingIndex, 1);
+    } else {
+      classes.push(className);
+      el.className = classes.join(' ');
+    }
+  }
+}
+
+function addClass(el, className) {
+  if (el.classList) {
+    el.classList.add(className);
+  } else {
+    el.className += ' ' + className;
+  }
+}
+
+function removeClass(el, className) {
+  if (el.classList) {
+    el.classList.remove(className);
+  } else {
+    el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
+  }
+}
+
+// $form.on('drag dragstart dragend dragover dragenter dragleave drop');
+function addListenerMulti(el, events, func) {
+  const eventsArray = events.split(' ');
+  for (let event in eventsArray) {
+    el.addEventListener(eventsArray[event], func, false);
+  }
+}
+
+export default {
+  toggleClass,
+  addClass,
+  removeClass,
+  addListenerMulti
+};

+ 131 - 42
src/plugins/DragDrop.js

@@ -1,77 +1,166 @@
+import Utils from '../core/Utils';
 import TransloaditPlugin from './TransloaditPlugin';
-
-// This is how we roll $('.element').toggleClass in non-jQuery world
-function toggleClass(el, className) {
-  // console.log(el);
-
-  if (el.classList) {
-    el.classList.toggle(className);
-  } else {
-    var classes = el.className.split(' ');
-    var existingIndex = classes.indexOf(className);
-
-    if (existingIndex >= 0) {
-      classes.splice(existingIndex, 1);
-    } else {
-      classes.push(className);
-      el.className = classes.join(' ');
-    }
-  }
-}
+// import Tus from 'tus-js-client';
 
 export default class DragDrop extends TransloaditPlugin {
   constructor(core, opts) {
     super(core, opts);
     this.type = 'selecter';
-    this.opts = opts;
+
+    // set default options
+    const defaultOptions = {
+      bla: 'blabla',
+      autoSubmit: true,
+      modal: true
+    };
+
+    // merge default options with the ones set by user
+    this.opts = defaultOptions;
+    Object.assign(this.opts, opts);
+
     console.log(this.opts);
 
     // get the element where Drag & Drop event will occur
     this.dropzone = document.querySelectorAll(this.opts.selector)[0];
+    this.dropzoneInput = document.querySelectorAll('.UppyDragDrop-input')[0];
+
+    this.status = document.querySelectorAll('.UppyDragDrop-status')[0];
+
+    this.isDragDropSupported = this.checkDragDropSupport();
 
     // crazy stuff so that ‘this’ will behave in class
-    this.handleDragEnter = this.handleDragEnter.bind(this);
-    this.handleDragOver = this.handleDragOver.bind(this);
+    this.listenForEvents = this.listenForEvents.bind(this);
     this.handleDrop = this.handleDrop.bind(this);
+    this.checkDragDropSupport = this.checkDragDropSupport.bind(this);
+    this.upload = this.upload.bind(this);
+    this.handleInputChange = this.handleInputChange.bind(this);
+  }
+
+  /**
+   * Checks if the browser supports Drag & Drop
+   */
+  checkDragDropSupport() {
+    const div = document.createElement('div');
+    return (('draggable' in div) ||
+           ('ondragstart' in div && 'ondrop' in div)) &&
+           'FormData' in window && 'FileReader' in window;
   }
 
   listenForEvents() {
-    this.dropzone.addEventListener('dragenter', this.handleDragEnter);
-    this.dropzone.addEventListener('dragover', this.handleDragOver);
+    if (this.isDragDropSupported) {
+      Utils.addClass(this.dropzone, 'is-dragdrop-supported');
+    }
+
+    // prevent default actions for all drag & drop events
+    Utils.addListenerMulti(this.dropzone, 'drag dragstart dragend dragover dragenter dragleave drop', (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+    });
+
+    // Toggle is-dragover state when files are dragged over or dropped
+    Utils.addListenerMulti(this.dropzone, 'dragover dragenter', () => {
+      Utils.addClass(this.dropzone, 'is-dragover');
+    });
+
+    Utils.addListenerMulti(this.dropzone, 'dragleave dragend drop', () => {
+      Utils.removeClass(this.dropzone, 'is-dragover');
+    });
+
     this.dropzone.addEventListener('drop', this.handleDrop);
+
+    this.dropzoneInput.addEventListener('change', this.handleInputChange);
+
     console.log(`waiting for some files to be dropped on ${this.opts.selector}`);
   }
 
-  handleDragEnter(e) {
-    event.stopPropagation();
-    event.preventDefault();
-    toggleClass(this.dropzone, 'is-dragover');
-  }
+  // Toggle is-dragover state when files are dragged over or dropped
+  // in this case — add/remove 'is-dragover' class
+  // toggleDragoverState(e) {
+  //   toggleClass(this.dropzone, 'is-dragover');
+  // }
 
-  handleDragOver(e) {
-    e.stopPropagation();
-    e.preventDefault();
+  displayStatus(status) {
+    this.status.innerHTML = status;
   }
 
   handleDrop(e) {
     console.log('all right, someone dropped something here...');
-    e.preventDefault();
-    toggleClass(this.dropzone, 'is-dragover');
     const files = e.dataTransfer.files;
-    console.log(files);
-    this.handleFiles(files);
+    const formData = new FormData(this.dropzone);
+    // console.log('pizza', formData);
+
+    for (var i = 0; i < files.length; i++) {
+      formData.append('file', files[i]);
+      console.log('pizza', files[i]);
+    }
+
+    this.upload(formData);
   }
 
-  handleFiles(files) {
-    return files;
+  handleInputChange() {
+    // const fileInput = document.querySelectorAll('.UppyDragDrop-input')[0];
+    const formData = new FormData(this.dropzone);
+    console.log('pizza', formData);
+
+    this.upload(formData);
   }
 
-  run(files) {
+  upload(data) {
+    this.displayStatus('Uploading...');
+
+    const request = new XMLHttpRequest();
+    request.open('POST', 'http://api2.transloadit.com', true);
+    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
+
+    request.addEventListener('load', () => {
+      console.log('fucking done!');
+      this.displayStatus('Done.');
+    });
+
+    request.addEventListener('load', () => {
+      this.displayStatus('Done.');
+    });
+
+    request.addEventListener('error', () => {
+      console.log('fucking error!');
+    });
+
+    request.send(data);
+
+    // Create a new tus upload
+    // const upload = new Tus.Upload(files, {
+    //   endpoint: 'http://master.tus.io:8080',
+    //   onError: function(error) {
+    //     console.log('Failed because: ' + error);
+    //   },
+    //   onProgress: function(bytesUploaded, bytesTotal) {
+    //     var percentage = (bytesUploaded / bytesTotal * 100).toFixed(2);
+    //     console.log(bytesUploaded, bytesTotal, percentage + '%');
+    //   },
+    //   onSuccess: function() {
+    //     console.log('Download %s from %s', upload.file.name, upload.url);
+    //   }
+    // });
+
+    // Start the upload
+    // upload.start();
+  }
+
+  run(files, done) {
+    console.dir({
+      method: 'DragDrop.run',
+      files : files,
+      done  : done
+    });
+
+    console.log('DragDrop running!');
+    // console.log(files);
     this.listenForEvents();
-    // this.core.setProgress(this, 0);
+    this.core.setProgress(this, 0);
     var selected = [ {name: 'lolcat.jpeg'} ];
-    // this.core.setProgress(this, 100);
-
+    this.core.setProgress(this, 100);
     // return selected;
+    done(null, 'done with DragDrop');
+    // return Promise.resolve('done with DragDrop');
   }
 }

+ 12 - 8
src/plugins/Tus10.js

@@ -6,17 +6,21 @@ export default class Tus10 extends TransloaditPlugin {
     this.type = 'uploader';
   }
 
-  run(files) {
+  run(files, done) {
+    // console.log(files);
     this.core.setProgress(this, 0);
     var uploaded = [];
-    for (var i in files) {
-      var file = files[i];
-      this.core.setProgress(this, (i * 1) + 1);
-      uploaded[i]     = file;
-      uploaded[i].url = this.opts.endpoint + '/uploaded/' + file.name;
-    }
+    // for (var i in files) {
+    //   var file = files[i];
+    //   this.core.setProgress(this, (i * 1) + 1);
+    //   uploaded[i]     = file;
+    //   uploaded[i].url = this.opts.endpoint + '/uploaded/' + file.name;
+    // }
     this.core.setProgress(this, 100);
 
-    return uploaded;
+    done(null, 'done with Tus');
+    // return Promise.resolve('done with Tus');
+
+    // return uploaded;
   }
 }

+ 5 - 5
src/plugins/index.js

@@ -1,11 +1,11 @@
-import TransloaditPlugin from './TransloaditPlugin'
-import DragDrop from './DragDrop'
-import TransloaditBasic from './TransloaditBasic'
-import Tus10 from './Tus10'
+import DragDrop from './DragDrop';
+import TransloaditBasic from './TransloaditBasic';
+import Tus10 from './Tus10';
+import TransloaditPlugin from './TransloaditPlugin';
 
 export default {
   TransloaditPlugin,
   DragDrop,
   TransloaditBasic,
   Tus10
-}
+};

BIN
uppy-core-plugins-architecture.jpg


+ 43 - 58
website/src/api/index.md

@@ -4,30 +4,47 @@ order: 0
 title: "Architecture"
 ---
 
-> This file might be slightly outdate. Current proposal as of 2015-11-23 is reflected in  [classes.es6](https://github.com/transloadit/uppy/blob/f1aa1072d5159c372624a57d5a8edaad2119efa9/classes.es6)
+# Uppy File Uploader Architecture
+
+*Work in progress, API not stable. Last update: 2015-12-03*
+
+## The Gist
+
+``` javascript
+import Uppy from './src/core';
+import { DragDrop, Tus10 } from './src/plugins';
+
+const uppy = new Uppy({wait: false});
+const files = uppy
+  .use(DragDrop, {selector: '#upload-target'})
+  .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
+  .run();
+```
 
 ## Core
 
-1. The core function `transloadit` accepts `options` and exposes methods like `.use` for adding plugins and `.set` for setting options.
-2. Each plugin is then called by the `use` with given `options` as an argument.
-3. The result is passed from the plugin to `prepareMedia` for some final processing
-4. Then the processed files go into `upload` which uploads everything to Transloadit servers, using `tus`.
+1. Core class `Uppy` accepts global object `options`, and exposes methods like `.use` for adding plugins and `.set` for setting options.
+2. We create a new instance of `Uppy` and call `.use` methods on that, passing the plugins and their options.
+3. Plugins have types: `presetter`, `selecter` and `uploader` (more types could be added in the future). When `use` is called, each plugin’s `run` method is added to an array of corresponding types, `methods`.
+4. Ok, here is the tricky part. Core’s method `run` iterates over plugin types in a waterfall manner — each `runTypes`  runs its `method`s in parallel and returns an array of results (files) to the next plugin type in the waterfall:
+
+![waterfall of parallels](uppy-core-plugins-architecture.jpg)
 
 ## Plugins
 
-1. Plugins should be registered like this:
+1. Plugins are registered like this:
 ```javascript
-  transloadit.use(dragndrop, {
-    selector: '.drop'
-  });
+uppy
+  .use(DragDrop, {selector: '#upload-target'})
+  .use(Tus10, {endpoint: 'http://master.tus.io:8080'})
 ```
 
-`dragndrop` here is function that we pass as an argument.
-*For reference, see [Markdown-It](https://github.com/markdown-it/markdown-it/blob/master/lib/index.js#L459).*
+Internally, plugins extend from a `UppyPlugin` class, see that for details.
 
-2. Settings and handlers should be chainable and set like this:
+
+2. Settings and handlers are chainable, set like this:
 ```javascript
-transloadit
+uppy
   .set({ wait: true })
   .use(transloaditModal, {some: 'config'})
   .use(dragdrop, {target: transloaditModal})
@@ -36,56 +53,24 @@ transloadit
   .on('error', handleError);
 ```
 
-3. In `transloadit-js` everything is a plugin: a `Modal` dialog, `Drag & Drop`, `Instagram`. We borrow general approach from the new Babel and PostCSS — almost barebones by default, each chunk of functionality exists as separate plugin — easier to pick and choose exactly what you need to get a lightweight solution for production, while also easier to develop and avoid merge conflicts.
-
-4. Presets should exist with basic plugins like `Modal` & `Drag & Drop`. This should let people who just want to get it working as quickly as possible get started in seconds:
-    ```javascript
-    transloadit
-      .set({ wait: true })
-      .use(transloaditBasic, {some: 'config'})
-    ```
-
-    *See [`es2015-preset`](https://babeljs.io/docs/plugins/preset-es2015/) for Babel and [`PreCSS`](https://github.com/jonathantneal/precss#plugins) for PostCSS.*
+3. In `Uppy` everything is a plugin: a `Modal` dialog, `Drag & Drop`, `Instagram`. We borrow general approach from the new Babel and PostCSS — each chunk of functionality exists as separate plugin — easier to pick and choose exactly what you need to get a lightweight solution for production, while also easier to develop and avoid merge conflicts.
 
-    or just make it a code sample for easy copy/pasting and future customizations (no need to change the main function call, just add/remove lines to modify behaviour):
-    ```javascript
-    transloadit
-      .set({ wait: true })
-      .use(transloaditModal, {some: 'config'})
-      .use(dragdrop, {target: transloaditModal})
-    ```
+4. There will be a simplified version that includes all the necessary plugins and sane defaults.
+```javascript
+uppyDist
+  .set({ wait: true })
+  .run();
+```
 
 5. Users should be able to set themes and style settings in config: `.use(myTheme)`.
 
 6. Would be cool if you could use whatever drag & drop library you wanted (DropZone) with our wrapper.
 
-## Usage
-
-```javascript
-import transloadit   from 'transloadit';
-import dragndrop     from 'transloadit-dragndrop';
-import instagram     from 'transloadit-instagram';
-import modal         from 'transloadit-modal';
-
-// import Transloadit from 'transloadit-client'
-// import { dropbox, instagram, dragdrop, webcam } from 'transloadit-client/plugins'
-
-// or to import all of them
-// import { * as plugins } from 'transloadit/plugins'
-
-transloadit
-  .set({ wait: true })
-  .use(modal, {some: 'config'})
-  .use(dragdrop, {target: transloaditModal})
-  .use(instagram, {some: 'config'})
-  .on('progress', handleProgress)
-  .on('error', handleError)
-  .on('done', handleResult);
-```
-
 ## References & Inspiration
 
-1. PostCSS
-2. Markdown-It
-3. Babel
-4. Lodash
+1. [PostCSS](https://github.com/postcss/postcss/blob/master/lib/postcss.es6#L19)
+2. [Markdown-It](https://github.com/markdown-it/markdown-it/blob/master/lib/index.js#L459)
+3. [Babel](babeljs.io)
+4. [Lodash](https://lodash.com/)
+5. [Vue.js](http://vuejs.org/guide/plugins.html#Using_a_Plugin)
+6. [Tus.js](https://github.com/tus/tus-js-client)