diff --git a/packages/component-wizard/src/components/FileDropzone.js b/packages/component-wizard/src/components/FileDropzone.js new file mode 100644 index 0000000000000000000000000000000000000000..b97ee67cca4c8f93d4932358cfc1675b3e0628de --- /dev/null +++ b/packages/component-wizard/src/components/FileDropzone.js @@ -0,0 +1,26 @@ +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 diff --git a/packages/component-wizard/src/components/FileDropzone.local.scss b/packages/component-wizard/src/components/FileDropzone.local.scss new file mode 100644 index 0000000000000000000000000000000000000000..fccfe9120bf2a32e4721e44813a3d7ab21d4d705 --- /dev/null +++ b/packages/component-wizard/src/components/FileDropzone.local.scss @@ -0,0 +1,12 @@ +.dropzone { + align-items: center; + display: flex; + height: 60px; + justify-content: center; + margin: 10px 0; + + span { + color: #888; + font-size: 14px; + } +} diff --git a/packages/component-wizard/src/components/FileItem.js b/packages/component-wizard/src/components/FileItem.js index d630b483f3838ec971a93bf3fa3702ad487b1c61..a87bb3333064a27cb1b964140025098ff1b3bddd 100644 --- a/packages/component-wizard/src/components/FileItem.js +++ b/packages/component-wizard/src/components/FileItem.js @@ -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> diff --git a/packages/component-wizard/src/components/FileItem.local.scss b/packages/component-wizard/src/components/FileItem.local.scss index 5e6d16ca97f87741459a3d88f0f3a1a6c11cdc94..076d3f0412ba3073bfe818bb7d0f565bee5185d4 100644 --- a/packages/component-wizard/src/components/FileItem.local.scss +++ b/packages/component-wizard/src/components/FileItem.local.scss @@ -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 { diff --git a/packages/component-wizard/src/components/FileSection.js b/packages/component-wizard/src/components/FileSection.js new file mode 100644 index 0000000000000000000000000000000000000000..6e5c6f58ad450c75384e36908ba44b3d15a97e8d --- /dev/null +++ b/packages/component-wizard/src/components/FileSection.js @@ -0,0 +1,102 @@ +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) diff --git a/packages/component-wizard/src/components/FileSection.local.scss b/packages/component-wizard/src/components/FileSection.local.scss new file mode 100644 index 0000000000000000000000000000000000000000..f69a27147b6f16a921a02175700b18e305185aef --- /dev/null +++ b/packages/component-wizard/src/components/FileSection.local.scss @@ -0,0 +1,46 @@ +.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; +} diff --git a/packages/component-wizard/src/components/Files.js b/packages/component-wizard/src/components/Files.js index fb7aa0a6606ba8aa1808046e756f520931ecb1ce..2f4be3cd116556a67f19262aed3fdb63ac05fbd9 100644 --- a/packages/component-wizard/src/components/Files.js +++ b/packages/component-wizard/src/components/Files.js @@ -1,80 +1,36 @@ 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, diff --git a/packages/component-wizard/src/components/Files.local.scss b/packages/component-wizard/src/components/Files.local.scss index 1f4c74db9550c731d1662c7414b2790942c50e78..5e6d16ca97f87741459a3d88f0f3a1a6c11cdc94 100644 --- a/packages/component-wizard/src/components/Files.local.scss +++ b/packages/component-wizard/src/components/Files.local.scss @@ -1,59 +1,3 @@ -.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; diff --git a/packages/component-wizard/src/components/WizardPage.js b/packages/component-wizard/src/components/WizardPage.js index da00a100ed26da75cd2736e9887894704777bfbd..500ee3c0b6a8ecde73863f78e5fdc73f88818fa9 100644 --- a/packages/component-wizard/src/components/WizardPage.js +++ b/packages/component-wizard/src/components/WizardPage.js @@ -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) diff --git a/packages/components-faraday/src/components/AuthorList/AuthorList.js b/packages/components-faraday/src/components/AuthorList/AuthorList.js index b287d67260c4d77f49bf77836a144bc8de75bb17..9576a82d93eea2f15673629b88232beafe349129 100644 --- a/packages/components-faraday/src/components/AuthorList/AuthorList.js +++ b/packages/components-faraday/src/components/AuthorList/AuthorList.js @@ -63,6 +63,7 @@ const Authors = ({ /> ) : ( <SortableList + beginDragProps={['index']} dragHandle={DragHandle} dropItem={dropItem} editedAuthor={editedAuthor} diff --git a/packages/components-faraday/src/components/SortableList/SortableList.js b/packages/components-faraday/src/components/SortableList/SortableList.js index 86f710b6db530e668b1454aab6ea5ca982a39685..9eca28a1feb282f1894ebd4cda0503fa1b7f6cf5 100644 --- a/packages/components-faraday/src/components/SortableList/SortableList.js +++ b/packages/components-faraday/src/components/SortableList/SortableList.js @@ -1,4 +1,5 @@ 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