Skip to content

Commit

Permalink
feat: extend dropzone to page (#942)
Browse files Browse the repository at this point in the history
- The dropzone was extended to the whole page
- We can now drop a file in any page: it is added to the root folder and the user redirected to the files page
- In the files page we can still drop the files in specific folders as before

![dropit](https://user-images.githubusercontent.com/33324750/51401787-98b0e780-1b43-11e9-965c-493dd9f4e2bd.gif)


Closes #916.
  • Loading branch information
fsdiogo authored Jan 24, 2019
1 parent 6926e40 commit 09f6de9
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 40 deletions.
55 changes: 49 additions & 6 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'redux-bundler-react'
import NavBar from './navigation/NavBar'
import navHelper from 'internal-nav-helper'
import { IpldExploreForm } from 'ipld-explorer-components'
import { DragDropContext } from 'react-dnd'
// React DnD
import { DragDropContext, DropTarget } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
import DnDBackend from './lib/dnd-backend'
// Components
import NavBar from './navigation/NavBar'
import ComponentLoader from './loader/ComponentLoader'
import Notify from './components/notify/Notify'
import Connected from './components/connected/Connected'
Expand All @@ -14,23 +17,41 @@ export class App extends Component {
static propTypes = {
doInitIpfs: PropTypes.func.isRequired,
doUpdateUrl: PropTypes.func.isRequired,
doUpdateHash: PropTypes.func.isRequired,
doFilesWrite: PropTypes.func.isRequired,
route: PropTypes.oneOfType([
PropTypes.func,
PropTypes.element
]).isRequired,
routeInfo: PropTypes.object.isRequired,
navbarIsOpen: PropTypes.bool.isRequired
navbarIsOpen: PropTypes.bool.isRequired,
// Injected by DropTarget
isOver: PropTypes.bool.isRequired
}

componentWillMount () {
this.props.doInitIpfs()
}

addFiles = (files) => {
const { doFilesWrite, doUpdateHash, routeInfo } = this.props

// Add the dropped files to the root
doFilesWrite('/', files)

// Change to the files pages if the user is not there
if (!routeInfo.url.startsWith('/files')) {
doUpdateHash('/files')
}
}

render () {
const { route: Page, ipfsReady, routeInfo: { url }, navbarIsOpen } = this.props
const { route: Page, ipfsReady, routeInfo: { url }, navbarIsOpen, connectDropTarget, isOver } = this.props

return (
return connectDropTarget(
<div className='sans-serif' onClick={navHelper(this.props.doUpdateUrl)}>
{/* Tinted overlay that appears when dragging and dropping an item */}
{ isOver && <div className='w-100 h-100 top-0 left-0 absolute' style={{ background: 'rgba(99, 202, 210, 0.2)' }} /> }
<div className='flex-l' style={{ minHeight: '100vh' }}>
<div className={`flex-none-l bg-navy ${navbarIsOpen ? 'w5-l' : 'w4-l'}`}>
<NavBar />
Expand Down Expand Up @@ -58,12 +79,34 @@ export class App extends Component {
}
}

const dropTarget = {
drop: (props, monitor, App) => {
if (monitor.didDrop()) {
return
}

const item = monitor.getItem()

App.addFiles(item)
}
}

const dropCollect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})

export const AppWithDropTarget = DropTarget(NativeTypes.FILE, dropTarget, dropCollect)(App)

export default connect(
'selectRoute',
'selectNavbarIsOpen',
'selectRouteInfo',
'doUpdateUrl',
'doUpdateHash',
'doInitIpfs',
'doFilesWrite',
'selectIpfsReady',
DragDropContext(DnDBackend)(App)
DragDropContext(DnDBackend)(AppWithDropTarget)
)
40 changes: 11 additions & 29 deletions src/files/file-input/FileInput.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { translate } from 'react-i18next'
// Icons
import DocumentIcon from '../../icons/StrokeDocument'
import FolderIcon from '../../icons/StrokeFolder'
import DecentralizationIcon from '../../icons/StrokeDecentralization'
// Components
import { Dropdown, DropdownMenu, Option } from '../dropdown/Dropdown'
import Overlay from '../../components/overlay/Overlay'
import ByPathModal from './ByPathModal'
import NewFolderModal from './NewFolderModal'
import { NativeTypes } from 'react-dnd-html5-backend'
import { DropTarget } from 'react-dnd'

const AddButton = translate('files')(({ progress = null, t, tReady, ...props }) => {
const sending = progress !== null
let cls = 'Button f6 relative transition-all sans-serif dib v-mid fw5 nowrap lh-copy bn br1 pa2 focus-outline'
if (sending) {
cls += ' bg-grey light-grey'
} else {
cls += ' pointer bg-green white'
}
const cls = classnames({
'bg-grey light-grey': sending,
'pointer bg-green white': !sending
}, ['Button f6 relative transition-all sans-serif dib v-mid fw5 nowrap lh-copy bn br1 pa2 focus-outline'])

return (
<button disabled={sending} className={cls} style={{ width: '144px' }} {...props}>
<div className='absolute top-0 left-0 1 pa2 w-100 z-2'>
{sending ? `${progress.toFixed(0)}%` : `+ ${t('addToIPFS')}`}
{ sending ? `${progress.toFixed(0)}%` : `+ ${t('addToIPFS')}` }
</div>&nbsp;

{ sending &&
<div className='transition-all absolute top-0 br1 left-0 h-100 z-1' style={{ width: `${progress}%`, background: 'rgba(0,0,0,0.1)' }} />
}
<div className='transition-all absolute top-0 br1 left-0 h-100 z-1' style={{ width: `${progress}%`, background: 'rgba(0,0,0,0.1)' }} /> }
</button>
)
})
Expand Down Expand Up @@ -96,7 +94,7 @@ class FileInput extends React.Component {
progress = 100
}

return this.props.connectDropTarget(
return (
<div className={this.props.className}>
<Dropdown>
<AddButton progress={progress} onClick={this.toggleDropdown} />
Expand Down Expand Up @@ -156,20 +154,4 @@ class FileInput extends React.Component {
}
}

const dropTarget = {
drop: ({ onAddFiles }, monitor) => {
if (monitor.didDrop()) {
return
}

onAddFiles(monitor.getItem())
}
}

const dropCollect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})

export default DropTarget(NativeTypes.FILE, dropTarget, dropCollect)(translate('files')(FileInput))
export default translate('files')(FileInput)
12 changes: 7 additions & 5 deletions src/files/file/File.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react'
import { findDOMNode } from 'react-dom'
import PropTypes from 'prop-types'
import { join, basename } from 'path'
import filesize from 'filesize'
// React DnD
import { DropTarget, DragSource } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
// Components
import Tooltip from '../../components/tooltip/Tooltip'
import Checkbox from '../../components/checkbox/Checkbox'
import FileIcon from '../file-icon/FileIcon'
import ContextMenu from '../context-menu/ContextMenu'
import Tooltip from '../../components/tooltip/Tooltip'
import { DropTarget, DragSource } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
import { join, basename } from 'path'

class File extends React.Component {
constructor (props) {
Expand Down Expand Up @@ -103,7 +105,7 @@ class File extends React.Component {
if (focused || (selected && !translucent) || coloured || (isOver && canDrop)) {
styles.backgroundColor = '#F0F6FA'
} else if (translucent) {
className += ' o-50'
className += ' o-70'
}

if (focused) {
Expand Down
1 change: 1 addition & 0 deletions src/files/files-list/FilesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ const dropTarget = {
}

const item = monitor.getItem()

onAddFiles(item)
}
}
Expand Down

0 comments on commit 09f6de9

Please sign in to comment.