mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-22 17:58:05 +00:00
Resolve conflicts during Dashboard merge to master
This commit is contained in:
commit
102a4e3ebd
12 changed files with 281 additions and 131 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -19,7 +19,6 @@ first Friday of every new month.
|
|||
Ideas that will be planned and find their way into a release at one point
|
||||
|
||||
- [ ] build: go over `package.json` together and clean up npm run scripts (@arturi, @hedgerh, @kvz)
|
||||
- [ ] build: browsersync does 3 refreshes, can that be one? should be doable via cooldown/debounce?
|
||||
- [ ] build: investigate Rollup someday, for tree-shaking and smaller dist https://github.com/substack/node-browserify/issues/1379#issuecomment-183383199, https://github.com/nolanlawson/rollupify
|
||||
- [ ] core: Decouple rendering from Plugins and try to make Uppy work with React (add basic example) to remain aware of possible issues (@hedgerh), look at https://github.com/akiran/react-slick
|
||||
- [ ] core: Have base styles, be explicit about fonts, etc
|
||||
|
|
@ -38,6 +37,7 @@ Ideas that will be planned and find their way into a release at one point
|
|||
- [ ] website: Make a gif/video of Uppy Modal or DragDrop demo (drag & drop a few files -> upload happens)
|
||||
- [ ] website: scrollbars on code samples (can’t reproduce!) (@arturi)
|
||||
- [ ] core: accessibility research
|
||||
- [ ] test: add next-update https://www.npmjs.com/package/next-update to check if packages we use can be safely updated
|
||||
|
||||
## 0.8.0
|
||||
|
||||
|
|
@ -58,15 +58,19 @@ Theme: Remote Uploads, UI Redesign
|
|||
|
||||
Released: July 1, 2016
|
||||
|
||||
- [ ] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh)
|
||||
- [ ] core: Rethink UI (@arturi)
|
||||
- [ ] server: add tus-js-client when it's node-ready (@hedgerh)
|
||||
- [ ] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh)
|
||||
- [x] core: Investigate if there is a way to manage an oauth dialog and not navigate away from Uppy; Put entire(?) state into oauth redirect urls / LocalStorage with an identifier ? (@hedgerh)
|
||||
- [x] core: Rethink UI: Part I (interface research for better file selection / progress representation) (@arturi)
|
||||
- [x] core: let user cancel uploads in progress (@arturi)
|
||||
- [x] core: resize image file previews (to 100x100px) for performance (@arturi)
|
||||
- [x] server: add tus-js-client when it's node-ready (@hedgerh)
|
||||
- [x] server: make uppy-server talk to uppy-client in the browser, use websockets. (@hedgerh)
|
||||
- [x] dashboard: new “workspace” plugin, main area that allows for drag & drop and shows progress/actions on files, inspired by ProgressDrawer
|
||||
- [x] website: add new logos and blog (@arturi)
|
||||
- [x] drive: Return `cb` after writing all files https://github.com/transloadit/uppy-server/commit/4f1795bc55869fd098a5c81a80edac504fa7324a#commitcomment-17385433 (@hedgerh)
|
||||
- [x] server: Make Google Drive files to actually upload to the endpoint (@hedgerh)
|
||||
- [x] build: browsersync does 3 refreshes, can that be one? should be doable via cooldown/debounce? -> get rid of require shortcuts (@arturi)
|
||||
- [x] build: regular + min + gzipped versions of the bundle (@arturi)
|
||||
- [x] workspace: interface research for better file selection / progress representation (@arturi)
|
||||
- [x] build: set up a simple and quick dev workflow — watch:example (@arturi)
|
||||
|
||||
## 0.6.4
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,15 @@
|
|||
<body>
|
||||
<h1>Uppy is here</h1>
|
||||
<button id="uppyModalOpener">Open Modal</button>
|
||||
|
||||
<link href="uppy.min.css" rel="stylesheet">
|
||||
<script src="bundle.js"></script>
|
||||
<script>
|
||||
// var uppy = new Uppy.Core({locales: Uppy.locales.ru_RU, debug: true})
|
||||
// .use(Uppy.plugins.Modal, {trigger: '#uppyModalOpener'})
|
||||
// .use(Uppy.plugins.Dashboard, {target: Uppy.plugins.Modal})
|
||||
// .use(Uppy.plugins.Dummy, {target: Uppy.plugins.Modal})
|
||||
// .run();
|
||||
// document.querySelector('#uppyModalOpener').click()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Translator from '../core/Translator'
|
|||
import prettyBytes from 'pretty-bytes'
|
||||
import yo from 'yo-yo'
|
||||
import ee from 'events'
|
||||
import UppySocket from './UppySocket'
|
||||
|
||||
/**
|
||||
* Main Uppy core
|
||||
|
|
@ -32,6 +33,7 @@ export default class Core {
|
|||
|
||||
this.translator = new Translator({locales: this.opts.locales})
|
||||
this.i18n = this.translator.translate.bind(this.translator)
|
||||
this.initSocket = this.initSocket.bind(this)
|
||||
|
||||
this.emitter = new ee.EventEmitter()
|
||||
|
||||
|
|
@ -334,4 +336,12 @@ export default class Core {
|
|||
// .catch((error) => this.log('Upload result -> failed:', error))
|
||||
// })
|
||||
}
|
||||
|
||||
initSocket (opts) {
|
||||
if (!this.socket) {
|
||||
this.socket = new UppySocket(opts)
|
||||
}
|
||||
|
||||
return this.socket
|
||||
}
|
||||
}
|
||||
|
|
|
|||
68
src/core/UppySocket.js
Normal file
68
src/core/UppySocket.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import ee from 'events'
|
||||
|
||||
export default class UppySocket {
|
||||
constructor (opts) {
|
||||
this.queued = []
|
||||
this.isOpen = false
|
||||
this.socket = new WebSocket(opts.target)
|
||||
this.emitter = new ee.EventEmitter()
|
||||
|
||||
this.socket.onopen = (e) => {
|
||||
this.isOpen = true
|
||||
|
||||
while (this.queued.length > 0 && this.isOpen) {
|
||||
const first = this.queued[0]
|
||||
this.send(first.action, first.payload)
|
||||
this.queued = this.queued.slice(1)
|
||||
}
|
||||
}
|
||||
|
||||
this.socket.onclose = (e) => {
|
||||
this.isOpen = false
|
||||
}
|
||||
|
||||
this._handleMessage = this._handleMessage.bind(this)
|
||||
|
||||
this.socket.onmessage = this._handleMessage
|
||||
|
||||
this.emit = this.emit.bind(this)
|
||||
this.on = this.on.bind(this)
|
||||
this.once = this.once.bind(this)
|
||||
this.send = this.send.bind(this)
|
||||
}
|
||||
|
||||
send (action, payload) {
|
||||
// attach uuid
|
||||
|
||||
if (!this.isOpen) {
|
||||
this.queued.push({action, payload})
|
||||
return
|
||||
}
|
||||
|
||||
this.socket.send(JSON.stringify({
|
||||
action,
|
||||
payload
|
||||
}))
|
||||
}
|
||||
|
||||
on (action, handler) {
|
||||
this.emitter.on(action, handler)
|
||||
}
|
||||
|
||||
emit (action, payload) {
|
||||
this.emitter.emit(action, payload)
|
||||
}
|
||||
|
||||
once (action, handler) {
|
||||
this.emitter.once(action, handler)
|
||||
}
|
||||
|
||||
_handleMessage (e) {
|
||||
try {
|
||||
const message = JSON.parse(e.data)
|
||||
this.emit(message.action, message.payload)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ export default class Google extends Plugin {
|
|||
super(core, opts)
|
||||
this.type = 'acquirer'
|
||||
this.id = 'GoogleDrive'
|
||||
this.titile = 'Google Drive'
|
||||
this.title = 'Google Drive'
|
||||
this.icon = yo`
|
||||
<svg class="UppyModalTab-icon" width="28" height="28" viewBox="0 0 16 16">
|
||||
<path d="M2.955 14.93l2.667-4.62H16l-2.667 4.62H2.955zm2.378-4.62l-2.666 4.62L0 10.31l5.19-8.99 2.666 4.62-2.523 4.37zm10.523-.25h-5.333l-5.19-8.99h5.334l5.19 8.99z"/>
|
||||
|
|
@ -16,13 +16,18 @@ export default class Google extends Plugin {
|
|||
`
|
||||
|
||||
this.files = []
|
||||
this.renderBrowserItem = this.renderBrowserItem.bind(this)
|
||||
this.filterItems = this.filterItems.bind(this)
|
||||
this.filterQuery = this.filterQuery.bind(this)
|
||||
|
||||
// Logic
|
||||
this.addFile = this.addFile.bind(this)
|
||||
this.getFolder = this.getFolder.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.logout = this.logout.bind(this)
|
||||
|
||||
// Visual
|
||||
this.renderBrowserItem = this.renderBrowserItem.bind(this)
|
||||
this.filterItems = this.filterItems.bind(this)
|
||||
this.filterQuery = this.filterQuery.bind(this)
|
||||
this.renderAuth = this.renderAuth.bind(this)
|
||||
this.renderBrowser = this.renderBrowser.bind(this)
|
||||
this.sortByTitle = this.sortByTitle.bind(this)
|
||||
this.sortByDate = this.sortByDate.bind(this)
|
||||
|
|
@ -33,6 +38,53 @@ export default class Google extends Plugin {
|
|||
|
||||
// merge default options with the ones set by user
|
||||
this.opts = Object.assign({}, defaultOptions, opts)
|
||||
|
||||
const host = this.opts.host.replace(/^https?:\/\//, '')
|
||||
|
||||
this.socket = this.core.initSocket({
|
||||
target: 'ws://' + host + '/'
|
||||
})
|
||||
|
||||
this.socket.on('google.auth.pass', () => {
|
||||
console.log('google.auth.pass')
|
||||
this.getFolder(this.core.getState().googleDrive.directory.id)
|
||||
})
|
||||
|
||||
this.socket.on('uppy.debug', (payload) => {
|
||||
console.log('GOOGLE DEBUG:')
|
||||
console.log(payload)
|
||||
})
|
||||
|
||||
this.socket.on('google.list.ok', (data) => {
|
||||
console.log('google.list.ok')
|
||||
let folders = []
|
||||
let files = []
|
||||
data.items.forEach((item) => {
|
||||
if (item.mimeType === 'application/vnd.google-apps.folder') {
|
||||
folders.push(item)
|
||||
} else {
|
||||
files.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
this.updateState({
|
||||
folders,
|
||||
files,
|
||||
authenticated: true
|
||||
})
|
||||
})
|
||||
|
||||
this.socket.on('google.list.fail', (data) => {
|
||||
console.log('google.list.fail')
|
||||
console.log(data)
|
||||
})
|
||||
|
||||
this.socket.on('google.auth.fail', () => {
|
||||
console.log('google.auth.fail')
|
||||
this.updateState({
|
||||
authenticated: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
install () {
|
||||
|
|
@ -56,18 +108,6 @@ export default class Google extends Plugin {
|
|||
this.target = this.mount(target, plugin)
|
||||
|
||||
this.checkAuthentication()
|
||||
.then((authenticated) => {
|
||||
this.updateState({authenticated})
|
||||
|
||||
if (authenticated) {
|
||||
return this.getFolder(this.core.getState().googleDrive.directory.id)
|
||||
}
|
||||
|
||||
return authenticated
|
||||
})
|
||||
.then((newState) => {
|
||||
this.updateState(newState)
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
|
@ -97,29 +137,7 @@ export default class Google extends Plugin {
|
|||
* @return {Promise} authentication status
|
||||
*/
|
||||
checkAuthentication () {
|
||||
return fetch(`${this.opts.host}/google/authorize`, {
|
||||
method: 'get',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status >= 200 && res.status <= 300) {
|
||||
return res.json()
|
||||
} else {
|
||||
this.updateState({
|
||||
authenticated: false,
|
||||
error: true
|
||||
})
|
||||
let error = new Error(res.statusText)
|
||||
error.response = res
|
||||
throw error
|
||||
}
|
||||
})
|
||||
.then((data) => data.isAuthenticated)
|
||||
.catch((err) => err)
|
||||
this.socket.send('google.auth')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,42 +145,9 @@ export default class Google extends Plugin {
|
|||
* @param {String} id Folder id
|
||||
* @return {Promise} Folders/files in folder
|
||||
*/
|
||||
getFolder (id = 'root') {
|
||||
return fetch(`${this.opts.host}/google/list?dir=${id}`, {
|
||||
method: 'get',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status >= 200 && res.status <= 300) {
|
||||
return res.json().then((data) => {
|
||||
// let result = Utils.groupBy(data.items, (item) => item.mimeType)
|
||||
let folders = []
|
||||
let files = []
|
||||
data.items.forEach((item) => {
|
||||
if (item.mimeType === 'application/vnd.google-apps.folder') {
|
||||
folders.push(item)
|
||||
} else {
|
||||
files.push(item)
|
||||
}
|
||||
})
|
||||
return {
|
||||
folders,
|
||||
files
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.handleError(res)
|
||||
let error = new Error(res.statusText)
|
||||
error.response = res
|
||||
throw error
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return err
|
||||
getFolder (dir = 'root') {
|
||||
this.socket.send('google.list', {
|
||||
dir
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -198,11 +183,10 @@ export default class Google extends Plugin {
|
|||
data: file,
|
||||
name: file.title,
|
||||
type: this.getFileType(file),
|
||||
isRemote: true,
|
||||
remote: {
|
||||
url: `${this.opts.host}/google/get?fileId=${file.id}`,
|
||||
body: {
|
||||
fileId: file.id
|
||||
action: 'google.get',
|
||||
payload: {
|
||||
id: file.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -211,10 +195,10 @@ export default class Google extends Plugin {
|
|||
}
|
||||
|
||||
handleError (response) {
|
||||
this.checkAuthentication()
|
||||
.then((authenticated) => {
|
||||
this.updateState({authenticated})
|
||||
})
|
||||
// this.checkAuthentication()
|
||||
// .then((authenticated) => {
|
||||
// this.updateState({authenticated})
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -237,10 +221,10 @@ export default class Google extends Plugin {
|
|||
authenticated: false,
|
||||
files: [],
|
||||
folders: [],
|
||||
directory: {
|
||||
directory: [{
|
||||
title: 'My Drive',
|
||||
id: 'root'
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
this.updateState(newState)
|
||||
|
|
@ -346,18 +330,24 @@ export default class Google extends Plugin {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render user authentication view
|
||||
* Render user authentication view
|
||||
*/
|
||||
renderAuth () {
|
||||
const state = btoa(JSON.stringify({
|
||||
redirect: location.href.split('#')[0]
|
||||
}))
|
||||
const link = `${this.opts.host}/connect/google`
|
||||
|
||||
const handleAuth = (e) => {
|
||||
e.preventDefault()
|
||||
const authWindow = window.open(link)
|
||||
this.socket.once('google.auth.complete', () => {
|
||||
console.log('google.auth.complete')
|
||||
authWindow.close()
|
||||
})
|
||||
}
|
||||
|
||||
const link = `${this.opts.host}/connect/google?state=${state}`
|
||||
return yo`
|
||||
<div class="UppyGoogleDrive-authenticate">
|
||||
<h1>You need to authenticate with Google before selecting files.</h1>
|
||||
<a href=${link}>Authenticate</a>
|
||||
<a onclick=${handleAuth}>Authenticate</a>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ export default class Tus10 extends Plugin {
|
|||
if (!file.isRemote) {
|
||||
uploaders.push(this.upload(file, current, total))
|
||||
} else {
|
||||
uploaders.push(this.uploadRemote(file, current, total))
|
||||
uploaders.push(this.upload(file, current, total))
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -103,29 +103,21 @@ export default class Tus10 extends Plugin {
|
|||
|
||||
uploadRemote (file, current, total) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(file.remote.url, {
|
||||
method: 'post',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(Object.assign({}, file.remote.body, {
|
||||
target: this.opts.endpoint
|
||||
}))
|
||||
const payload = Object.assign({}, file.remote.payload, {
|
||||
target: this.opts.endpoint,
|
||||
protocol: 'tus'
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status >= 200 && res.status <= 300) {
|
||||
this.core.log(`Remote upload of '${file.name}' successful`)
|
||||
return resolve('Success')
|
||||
}
|
||||
this.core.log(`Remote upload of file '${file.name}' failed`)
|
||||
this.core.socket.send(file.remote.action, payload)
|
||||
this.core.socket.once('upload-success', () => {
|
||||
console.log('success')
|
||||
this.core.emitter.emit('upload-success', file)
|
||||
|
||||
if (file.acquiredBy.handleError) {
|
||||
file.acquiredBy.handleError(res)
|
||||
}
|
||||
this.core.emitter.emit('upload-progress', {
|
||||
id: file.id,
|
||||
percentage: 100
|
||||
})
|
||||
|
||||
return reject(new Error('Error: ' + res.statusText))
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
title: Uppy Begins
|
||||
date: 2015-10-26
|
||||
---
|
||||
|
||||
> On November 26 we gathered in Skype and that’s how Uppy was born. We didn’t know it would be called Uppy yet.
|
||||
|
|
@ -1,8 +1,46 @@
|
|||
---
|
||||
title: Uppy 0.6.0 Released
|
||||
date: 2016-06-04
|
||||
title: Uppy version 0.6.0 released
|
||||
date: 2016-06-30
|
||||
author: arturi
|
||||
published: false
|
||||
---
|
||||
|
||||
> Hi! We released Uppy 0.6.0. It was mainly a refactor release, but nonetheless very important, so we are proud.
|
||||
We are happy to announce that we have just released Uppy 0.6.0. Even though it was mainly a refactor release, we have nonetheless also managed to teach Uppy a few neat and important new tricks, and we are quite proud of that.
|
||||
|
||||
<!-- more -->
|
||||
We are still working hard on getting Uppy ready to meet the world as soon as possible. We aim to keep you updated on our development progress. In that light, let's go over the most important changes for this release.
|
||||
|
||||
## File Previews and Remote File Handling
|
||||
|
||||
* We have made a few changes that will help to improve visual clarity: Uppy now shows previews for images, and specific file icons for other types of files.
|
||||
* It is now also possible to select remote files in Uppy. Simply double-click a file from, for instance, Google Drive, and Uppy will then show it in a preview area. Good boy, Uppy!
|
||||
|
||||
## Accessibility and Acceptance Tests Stats
|
||||
|
||||
* We have been doing some more work on accessibility: from now on, when you switch tabs in Modal, it will focus on the first input in that tab.
|
||||
* Everybody likes to see stats. That is why, on our website, you can now [view stats]((http://uppy.io/stats)) that show how acceptance tests are performing in various browsers. If a test is successful, that means Uppy will likely be able to load and upload files in that particular browser.
|
||||
|
||||
## Release Notes
|
||||
|
||||
Below, you can read the full list of changes for version 0.6.0.
|
||||
|
||||
- build: minification of the bundle (@arturi)
|
||||
- build: revisit sourcemaps for production. can we have them without a mandatory extra request?
|
||||
- build: supply Uppy es5 and es6 entry points in npm package (@arturi)
|
||||
- build: switch to https://www.npmjs.com/package/npm-run-all instead of parallelshell (@arturi)
|
||||
- drive: Make sure uppy-server does not explode on special file types: https://dl.dropboxusercontent.com/s/d4dbxitjt8clo50/2016-05-06%20at%2022.41.png (@hedgerh)
|
||||
- modal: accessibility. focus on the first input field / button in tab panel (@arturi)
|
||||
- progressdrawer: figure out crazy rerendering of previews by yoyo/bel: https://github.com/shama/bel/issues/26, https://github.com/shama/bel/issues/27 (@arturi)
|
||||
- core: substantial refactor of mount & rendering (@arturi)
|
||||
- core: better state change logs for better debugging (@arturi)
|
||||
- progressdrawer: improve styles, add preview icons for all (@arturi)
|
||||
- server: Start implementing the `SERVER-PLAN.md`, remote files should be added to `state.files` and marked as `remote` (@hedgerh)
|
||||
- test: Add pass/fail Saucelabs flag to acceptance tests (@arturi)
|
||||
- website: Polish Saucelabs stats (social badge + stats layout) (@arturi)
|
||||
- meta: Create Uppy logos (@markstory)
|
||||
- website: fix examples and cleanup (@arturi)
|
||||
- website: Add Saucelabs badges to uppy.io (@kvz)
|
||||
- website: fix disappearing icons issue, `postcss-inline-svg` (@arturi)
|
||||
|
||||
We hope you enjoy this release. You will find us scratching at your door when we have more news!
|
||||
|
||||
The Uppy Team
|
||||
|
|
|
|||
41
website/src/_posts/2016-06-uppy-begins.md
Normal file
41
website/src/_posts/2016-06-uppy-begins.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: "Uppy: let’s teach an old dog some new tricks"
|
||||
date: 2016-06-28
|
||||
author: arturi
|
||||
---
|
||||
|
||||
For the past six months, we have been working hard on uppy.io. We feel that it is high time we gave you a look behind the scenes: what are we working on, and why.
|
||||
|
||||
The way uploading works has not changed in a meaningful way since the days of our trusty old 56 kbit/s modems. Of course, files have gotten bigger and speeds have increased, but that is more or less all there is to say. If it were up to us – and we hope it is – that is all about to change.
|
||||
|
||||
We at [Transloadit](https://transloadit.com/) are on a mission to change the way the world does uploading. To accomplish this, our first step has been to develop an open protocol for resumable file uploads, called [‘tus’](http://tus.io/). Finally, that 2GB video upload from your smartphone doesn’t have to start over when your train passes through a tunnel! The protocol got [Hacker News excited](https://news.ycombinator.com/item?id=10591348) on several occasions and is being deployed by, among others, our friends at Vimeo. Now that a stable version 1.0 of ‘tus’ has been released, it is time to put it to the test. A protocol without real-world applications is nothing more than a meaningless document, after all.
|
||||
|
||||
We are therefore excited to tell you about Uppy: the file uploader that will certainly fetch more than just your newspaper.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
### Why the need for another file uploader?
|
||||
|
||||
It is true, there are indeed already a good few file uploading solutions out there ([Dropzone](http://www.dropzonejs.com/), for instance, is quite good). And – for the most part – they do their job. Nevertheless, they are quite limited in their functionality:
|
||||
|
||||
* You can drag and drop files from local disk, but uploaders that supports Instagram, Dropbox or Google Drive are scarce. The ones out there lock you in with vendors and are hard to customize for own use.
|
||||
|
||||
* File uploaders are seldom mindful of the existence of encoding and processing backends, while the reality is that files often require some form of processing and that the end user would like to receive progress updates with regard to that.
|
||||
|
||||
* None of the currently available file uploaders make use of the standardized resumability that ‘tus’ provides, which makes them less than ideal for handling larger files.
|
||||
|
||||
* Lastly, we feel that the current solutions are sometimes dropping the ball when it comes to a polished user experience. We aim to fix that.
|
||||
|
||||
All in all, we think there is definitely some ‘trouble at the old mill’ here and it’s time to let Uppy take care of that!
|
||||
|
||||
### Our plans for Uppy
|
||||
|
||||
Uppy will be a JavaScript file uploader that allows you to fetch files, not only from your local disk, but also from places like Dropbox, Instagram, Google Drive, webcams and remote URLs. It will have a modular, plugin-based design, making it lightweight and customizable.
|
||||
Cute on the outside, the core of Uppy is very robust – thanks to resumability through 'tus'. We are confident that Uppy will be able to send even the biggest of files over the smallest of tubes.
|
||||
Uppy will also offer first class support for accessing Transloadit’s uploading and encoding backend, making it incredibly versatile. Of course, these are all ultimately just plugins, and Uppy can just as easily be used with your own backend – meaning no need to pay any subscription fees.
|
||||
|
||||
We are intent on making the user experience as smooth and satisfying as possible, in terms of both functionality and visual design. Uppy will have a beautiful, themeable UI and it will look – and work – great on mobile platforms as well. While we hope that advanced users will love the customizable nature of Uppy, an ample selection of presets will also be there to make sure that novice users are not going to be lost in the woods.
|
||||
|
||||
Lastly, and this is a point of special significance to us, Uppy will be completely open source. When Uppy is finished, you will be free to use it for whatever you like. Until that time, we very much welcome your ideas and contributions. There are still a lot of decisions to be made and this is the perfect time to come and influence the end product.
|
||||
|
||||
We are going to work hard on bringing you the best file uploader possible and we’ll keep you informed about the development process on [uppy.io](http://uppy.io/). We can’t wait for you to meet Uppy!
|
||||
|
|
@ -8,4 +8,5 @@
|
|||
<li><a href="/api/" class="nav-link<%- page.path.match(/api/) ? ' current' : '' %>">API</a></li>
|
||||
<li><a href="/examples/bundle/" class="nav-link<%- page.path.match(/examples/) ? ' current' : '' %>">Examples</a></li>
|
||||
<li><a href="/stats/" class="nav-link<%- page.path.match(/stats/) ? ' current' : '' %>">Stats</a></li>
|
||||
<!-- <li><a href="/blog/" class="nav-link<%- page.path.match(/blog/) ? ' current' : '' %>">Blog</a></li> -->
|
||||
<li><a href="https://github.com/transloadit/uppy" class="nav-link">Github</a></li>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="Sidebar js-Sidebar">
|
||||
<div class="Sidebar">
|
||||
<div class="list">
|
||||
<h2>Recent Posts</h2>
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -47,16 +47,21 @@
|
|||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
line-height: 1.8em;
|
||||
line-height: 1.4em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.menu-root {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.menu-sub {
|
||||
font-size: .85em;
|
||||
margin: 0.8em 0;
|
||||
}
|
||||
|
||||
.sidebar-link {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue