Skip to content
Snippets Groups Projects
Commit c355518d authored by Alexandru Munteanu's avatar Alexandru Munteanu
Browse files

Add file dragging

parent 8e098fbf
No related branches found
No related tags found
No related merge requests found
Showing
with 232 additions and 124 deletions
import React from 'react'
import classnames from 'classnames'
import classes from './FileDropzone.local.scss'
const FileDropzone = ({ ...props }) => (
<div className={classnames(classes.dropzone)}>
<span>Drag items here or use the upload button</span>
</div>
)
// export default compose(
// DropTarget(
// 'item',
// {
// drop(props) {
// console.log('s-a dat drop', props)
// },
// },
// (connect, monitor) => ({
// connectDropTarget: connect.dropTarget(),
// }),
// ),
// )(FileDropzone)
export default FileDropzone
.dropzone {
align-items: center;
display: flex;
height: 60px;
justify-content: center;
margin: 10px 0;
span {
color: #888;
font-size: 14px;
}
}
......@@ -4,25 +4,30 @@ import { Icon } from '@pubsweet/ui'
import classes from './FileItem.local.scss'
const parseFileSize = size => {
const kbSize = size / 1000
const mbSize = kbSize / 1000
const gbSize = mbSize / 1000
if (Math.floor(gbSize)) {
return `${Math.floor(gbSize)} GB`
} else if (Math.floor(mbSize)) {
return `${Math.floor(mbSize)} MB`
}
return `${Math.floor(kbSize)} kB`
}
const FileItem = ({ dragHandle, name, size, removeFile }) => (
<div className={classnames(classes['file-item'])}>
{dragHandle}
<div className={classnames(classes.info)}>
<span>{name}</span>
<span>{size}</span>
<span>{parseFileSize(size)}</span>
</div>
<div className={classnames(classes.buttons)}>
<button onClick={removeFile(name)} title="Preview">
<Icon color="#666">eye</Icon>
</button>
<button
onClick={e => {
e.preventDefault()
}}
title="Download"
>
<Icon color="#666">download</Icon>
</button>
<button onClick={removeFile(name)} title="Delete">
<Icon color="#666">trash-2</Icon>
</button>
......
......@@ -8,7 +8,8 @@
border-right: 1px solid black;
display: flex;
flex: 1;
padding: 2px 0;
justify-content: space-between;
padding: 2px 10px 2px 0;
}
.buttons {
......
import React from 'react'
import { compose } from 'recompose'
import classnames from 'classnames'
import { Icon } from '@pubsweet/ui'
import { DropTarget } from 'react-dnd'
import { NativeTypes } from 'react-dnd-html5-backend'
import { SortableList } from 'pubsweet-components-faraday/src/components'
import FileItem from './FileItem'
import FilePicker from './FilePicker'
import FileDropzone from './FileDropzone'
import classes from './FileSection.local.scss'
const DragHandle = () => (
<div className={classnames(classes['drag-handle'])}>
<Icon size={14}>chevron_up</Icon>
<Icon size={10}>menu</Icon>
<Icon size={14}>chevron_down</Icon>
</div>
)
const FileSection = ({
title,
files,
listId,
isLast,
isFirst,
addFile,
moveItem,
removeFile,
connectDropTarget,
isOver,
canDrop,
connectFileDrop,
isFileOver,
}) =>
connectFileDrop(
connectDropTarget(
<div
className={classnames({
[classes['drop-section']]: true,
[classes['no-border-top']]: !isFirst,
[classes['dashed-border']]: !isLast,
[classes['is-over']]: isFileOver || (isOver && canDrop),
})}
>
<div className={classnames(classes.header)}>
<span className={classnames(classes.title)}>{title}</span>
<FilePicker onUpload={addFile}>
<div className={classnames(classes['upload-button'])}>
<Icon>file-plus</Icon>
</div>
</FilePicker>
</div>
<SortableList
beginDragProps={['index', 'name', 'listId']}
dragHandle={DragHandle}
items={files}
listId={listId}
listItem={FileItem}
moveItem={moveItem}
removeFile={removeFile}
/>
<FileDropzone />
</div>,
),
)
export default compose(
DropTarget(
'item',
{
drop({ changeList, listId: toListId }, monitor) {
const { listId: fromListId, name } = monitor.getItem()
if (toListId === fromListId) return
changeList(fromListId, toListId, name)
},
canDrop({ listId: toListId }, monitor) {
const { listId: fromListId } = monitor.getItem()
return toListId !== fromListId
},
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
),
DropTarget(
NativeTypes.FILE,
{
drop({ addFile }, monitor) {
const [file] = monitor.getItem().files
addFile(file)
},
},
(connect, monitor) => ({
connectFileDrop: connect.dropTarget(),
isFileOver: monitor.isOver(),
}),
),
)(FileSection)
.drop-section {
border: 1px solid black;
display: flex;
flex-direction: column;
padding: 5px;
.header {
align-items: center;
display: flex;
justify-content: flex-start;
.upload-button {
cursor: pointer;
display: flex;
margin-left: 5px;
}
.title {
margin: 5px;
text-transform: uppercase;
}
}
}
.no-border-top {
border-top: none;
}
.dashed-border {
border-bottom: 1px dashed black;
}
.drag-handle {
align-items: center;
border-right: 1px solid black;
cursor: move;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 10px;
padding: 3px;
}
.is-over {
background-color: #ddd;
}
import React from 'react'
import classnames from 'classnames'
import { Icon } from '@pubsweet/ui'
import { compose, withState, withHandlers } from 'recompose'
import { SortableList } from 'pubsweet-components-faraday/src/components'
import classes from './Files.local.scss'
import FileSection from './FileSection'
import FilePicker from './FilePicker'
import FileItem from './FileItem'
const DragHandle = () => (
<div className={classnames(classes['drag-handle'])}>
<Icon size={14}>chevron_up</Icon>
<Icon size={10}>menu</Icon>
<Icon size={14}>chevron_down</Icon>
</div>
)
const DropSection = ({
files,
title,
isFirst,
isLast,
moveItem,
addFile,
removeFile,
}) => (
<div
className={classnames({
[classes['drop-section']]: true,
[classes['no-border-top']]: !isFirst,
[classes['dashed-border']]: !isLast,
})}
>
<div className={classnames(classes.header)}>
<span className={classnames(classes.title)}>{title}</span>
<FilePicker onUpload={addFile}>
<div className={classnames(classes['upload-button'])}>
<Icon>file-plus</Icon>
</div>
</FilePicker>
</div>
<SortableList
dragHandle={DragHandle}
items={files}
listItem={FileItem}
moveItem={moveItem}
removeFile={removeFile}
/>
<div className={classnames(classes.empty)}>
<span>Drag items here or use the upload button</span>
</div>
</div>
)
const Files = ({ files, addFile, moveItem, removeFile }) => (
<div className={classnames(classes.container)}>
<DropSection
const Files = ({ files, addFile, moveItem, removeFile, changeList }) => (
<div>
<FileSection
addFile={addFile('main')}
changeList={changeList}
files={files.main}
isFirst
listId="main"
moveItem={moveItem('main')}
removeFile={removeFile('main')}
title="Main manuscript"
/>
<DropSection
<FileSection
addFile={addFile('supplemental')}
changeList={changeList}
files={files.supplemental}
listId="supplemental"
moveItem={moveItem('supplemental')}
removeFile={removeFile('supplemental')}
title="Supplemental files"
/>
<DropSection
<FileSection
addFile={addFile('letter')}
changeList={changeList}
files={files.letter}
isLast
listId="letter"
moveItem={moveItem('letter')}
removeFile={removeFile('letter')}
title="Cover letter"
......@@ -85,6 +41,14 @@ const Files = ({ files, addFile, moveItem, removeFile }) => (
export default compose(
withState('files', 'changeFiles', { main: [], supplemental: [], letter: [] }),
withHandlers({
changeList: ({ files, changeFiles }) => (fromListId, toListId, name) => {
const changedFile = files[fromListId].find(f => f.name === name)
changeFiles(prev => ({
...prev,
[fromListId]: prev[fromListId].filter(f => f.name !== name),
[toListId]: [...prev[toListId], changedFile],
}))
},
addFile: ({ changeFiles }) => type => file => {
changeFiles(prev => ({
...prev,
......
.drop-section {
border: 1px solid black;
display: flex;
flex-direction: column;
padding: 5px;
.empty {
align-items: center;
display: flex;
height: 60px;
justify-content: center;
margin: 10px 0;
span {
color: #888;
font-size: 14px;
}
}
.header {
align-items: center;
display: flex;
justify-content: flex-start;
.upload-button {
cursor: pointer;
display: flex;
margin-left: 5px;
}
.title {
margin: 5px;
text-transform: uppercase;
}
}
}
.no-border-top {
border-top: none;
}
.dashed-border {
border-bottom: 1px dashed black;
}
.drag-handle {
align-items: center;
border-right: 1px solid black;
cursor: move;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 10px;
padding: 3px;
}
.file-item {
align-items: center;
border: 1px solid black;
......
......@@ -6,6 +6,8 @@ import { withJournal } from 'xpub-journal'
import { ConnectPage } from 'xpub-connect'
import { selectCollection, selectFragment } from 'xpub-selectors'
import { compose, withHandlers, withState, withContext } from 'recompose'
import HTML5Backend from 'react-dnd-html5-backend'
import { DragDropContext } from 'react-dnd'
import Wizard from './Wizard'
......@@ -78,4 +80,5 @@ export default compose(
toggleConfirmation,
}),
),
DragDropContext(HTML5Backend),
)(Wizard)
......@@ -63,6 +63,7 @@ const Authors = ({
/>
) : (
<SortableList
beginDragProps={['index']}
dragHandle={DragHandle}
dropItem={dropItem}
editedAuthor={editedAuthor}
......
import React from 'react'
import { pick } from 'lodash'
import { compose } from 'recompose'
import { findDOMNode } from 'react-dom'
import HTML5Backend from 'react-dnd-html5-backend'
......@@ -6,7 +7,9 @@ import { DragSource, DropTarget, DragDropContext } from 'react-dnd'
const itemSource = {
beginDrag(props) {
return { index: props.index }
console.log('beginning drag', props)
// return { index: props.index }
return pick(props, props.beginDragProps)
},
}
......@@ -124,4 +127,5 @@ SortableList.moveItem = (items, dragIndex, hoverIndex) => {
]
}
export default DragDropContext(HTML5Backend)(SortableList)
// export default DragDropContext(HTML5Backend)(SortableList)
export default SortableList
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment