From 9308cab1df0b3cd6fa790fab6046857b6c87a315 Mon Sep 17 00:00:00 2001 From: Alf Eaton <eaton.alf@gmail.com> Date: Tue, 12 Sep 2017 15:12:26 +0100 Subject: [PATCH] Add file attachments to review + decision forms Refactor Files molecule to allow subclassing as Attachments and Supplementary. --- src/atoms/Attachment.js | 20 ++++++++++++++++ src/atoms/Attachment.local.scss | 15 ++++++++++++ src/atoms/Attachment.md | 10 ++++++++ src/atoms/File.js | 2 +- src/index.js | 3 +++ src/molecules/Attachments.js | 35 ++++++++++++++++++++++++++++ src/molecules/Attachments.local.scss | 13 +++++++++++ src/molecules/Attachments.md | 18 ++++++++++++++ src/molecules/Files.js | 15 +++++------- src/molecules/Files.md | 3 +++ src/molecules/Supplementary.js | 28 ++++++++++++++++++++++ src/molecules/Supplementary.md | 18 ++++++++++++++ src/molecules/Upload.js | 10 ++------ 13 files changed, 172 insertions(+), 18 deletions(-) create mode 100644 src/atoms/Attachment.js create mode 100644 src/atoms/Attachment.local.scss create mode 100644 src/atoms/Attachment.md create mode 100644 src/molecules/Attachments.js create mode 100644 src/molecules/Attachments.local.scss create mode 100644 src/molecules/Attachments.md create mode 100644 src/molecules/Supplementary.js create mode 100644 src/molecules/Supplementary.md diff --git a/src/atoms/Attachment.js b/src/atoms/Attachment.js new file mode 100644 index 000000000..8aa508d41 --- /dev/null +++ b/src/atoms/Attachment.js @@ -0,0 +1,20 @@ +import React from 'react' +import Icon from './Icon' +import classes from './Attachment.local.scss' + +const Attachment = ({ value }) => ( + <a + key={value.url} + download={value.name} + href={value.url} + className={classes.attachment}> + <span className={classes.icon}> + <Icon color="cornflowerblue">paperclip</Icon> + </span> + <span className={classes.filename}> + {value.name} + </span> + </a> +) + +export default Attachment diff --git a/src/atoms/Attachment.local.scss b/src/atoms/Attachment.local.scss new file mode 100644 index 000000000..86fc8df67 --- /dev/null +++ b/src/atoms/Attachment.local.scss @@ -0,0 +1,15 @@ +.attachment { + display: flex; + align-items: center; + color: inherit; + text-decoration: none; +} + +.icon { + margin-right: 10px; + display: inline-flex; +} + +.filename { + font-family: var(--font-mono); +} diff --git a/src/atoms/Attachment.md b/src/atoms/Attachment.md new file mode 100644 index 000000000..3156671c6 --- /dev/null +++ b/src/atoms/Attachment.md @@ -0,0 +1,10 @@ +A file attached to a note. + +```js +const value = { + name: faker.system.commonFileName(), + url: faker.internet.url() +}; + +<Attachment value={value}/> +``` diff --git a/src/atoms/File.js b/src/atoms/File.js index 975470d80..4eca93ba0 100644 --- a/src/atoms/File.js +++ b/src/atoms/File.js @@ -3,7 +3,7 @@ import classes from './File.local.scss' const extension = ({ name }) => name.replace(/^.+\./, '') -const File = ({ value, file, error, progress }) => ( +const File = ({ value }) => ( <div className={classes.root}> <div className={classes.icon}> <div className={classes.extension}> diff --git a/src/index.js b/src/index.js index 3ed466791..402dfcebe 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ /* atom */ +export { default as Attachment } from './atoms/Attachment' export { default as Button } from './atoms/Button' export { default as Checkbox } from './atoms/Checkbox' export { default as Icon } from './atoms/Icon' @@ -10,7 +11,9 @@ export { default as ValidatedField } from './atoms/ValidatedField' /* molecules */ export { default as AppBar } from './molecules/AppBar' +export { default as Attachments } from './molecules/Attachments' export { default as CheckboxGroup } from './molecules/CheckboxGroup' export { default as Files } from './molecules/Files' +export { default as Supplementary } from './molecules/Supplementary' export { default as RadioGroup } from './molecules/RadioGroup' export { default as YesOrNo } from './molecules/YesOrNo' diff --git a/src/molecules/Attachments.js b/src/molecules/Attachments.js new file mode 100644 index 000000000..445ec1af6 --- /dev/null +++ b/src/molecules/Attachments.js @@ -0,0 +1,35 @@ +import React from 'react' +import Files from './Files' +import Attachment from '../atoms/Attachment' +import classes from './Attachments.local.scss' +import Icon from '../atoms/Icon' + +// TODO: show upload progress + +class Attachments extends React.Component { + render () { + return ( + <Files + {...this.props} + buttonText="Attach file" + uploadingFile={({ file, progress, error }) => ( + <div className={classes.uploading}> + <span className={classes.icon}> + <Icon color="cornflowerblue">paperclip</Icon> + </span> + <span className={classes.filename}> + {error ? error : 'Uploading…'} + </span> + </div> + )} + uploadedFile={value => ( + <Attachment + key={value.url} + value={value}/> + )} + /> + ) + } +} + +export default Attachments diff --git a/src/molecules/Attachments.local.scss b/src/molecules/Attachments.local.scss new file mode 100644 index 000000000..49bf28610 --- /dev/null +++ b/src/molecules/Attachments.local.scss @@ -0,0 +1,13 @@ +.uploading { + display: flex; + align-items: center; +} + +.icon { + color: gray; + margin-right: 10px; +} + +.filename { + color: gray; +} diff --git a/src/molecules/Attachments.md b/src/molecules/Attachments.md new file mode 100644 index 000000000..01dbde245 --- /dev/null +++ b/src/molecules/Attachments.md @@ -0,0 +1,18 @@ +A list of files attached to a note, and a button to attach a new file. + +```js +const value = [ + { + name: faker.system.commonFileName(), + url: faker.internet.url() + }, + { + name: faker.system.commonFileName(), + url: faker.internet.url() + } +]; + +<Attachments + value={value} + uploadFile={file => new XMLHttpRequest()}/> +``` diff --git a/src/molecules/Files.js b/src/molecules/Files.js index e6dc89f78..cc5291619 100644 --- a/src/molecules/Files.js +++ b/src/molecules/Files.js @@ -1,7 +1,6 @@ import React from 'react' import classes from './Files.local.scss' import Upload from './Upload' -import File from '../atoms/File' class Files extends React.Component { constructor (props) { @@ -46,7 +45,7 @@ class Files extends React.Component { } render () { - const { name } = this.props + const { name, buttonText, uploadingFile, uploadedFile } = this.props const { values, uploads } = this.state return ( @@ -56,7 +55,7 @@ class Files extends React.Component { type="button" className={classes.button} onClick={() => this.fileInput.click()}> - ▲ Upload files + {buttonText} </button> <input @@ -74,14 +73,12 @@ class Files extends React.Component { key={upload.file.name} file={upload.file} request={upload.request} - handleUploadedFile={this.handleUploadedFile}/> + handleUploadedFile={this.handleUploadedFile} + render={uploadingFile} + /> ))} - {values && values.map(value => ( - <File - key={value.name} - value={value}/> - ))} + {values && values.map(uploadedFile)} </div> </div> ) diff --git a/src/molecules/Files.md b/src/molecules/Files.md index 568f26f6f..0042861aa 100644 --- a/src/molecules/Files.md +++ b/src/molecules/Files.md @@ -15,5 +15,8 @@ const value = [ <Files value={value} + buttonText="Choose a file to upload" + uploadingFile={({ file, progress, error }) => <div style={{color:'gray'}}>{file.name}</div>} + uploadedFile={value => <div>{value.name}</div>} uploadFile={file => new XMLHttpRequest()}/> ``` diff --git a/src/molecules/Supplementary.js b/src/molecules/Supplementary.js new file mode 100644 index 000000000..6095f48ba --- /dev/null +++ b/src/molecules/Supplementary.js @@ -0,0 +1,28 @@ +import React from 'react' +import Files from './Files' +import UploadingFile from '../atoms/UploadingFile' +import File from '../atoms/File' + +class Supplementary extends React.Component { + render () { + return ( + <Files + {...this.props} + buttonText="▲ Upload files" + uploadingFile={({ file, progress, error }) => ( + <UploadingFile + key={file.name} + file={file} + progress={progress} + error={error}/> + )} + uploadedFile={value => ( + <File + key={value.url} + value={value}/> + )}/> + ) + } +} + +export default Supplementary diff --git a/src/molecules/Supplementary.md b/src/molecules/Supplementary.md new file mode 100644 index 000000000..c95a11fb4 --- /dev/null +++ b/src/molecules/Supplementary.md @@ -0,0 +1,18 @@ +A list of supplementary files, and a button to upload a new file. + +```js +const value = [ + { + name: faker.system.commonFileName(), + url: faker.internet.url() + }, + { + name: faker.system.commonFileName(), + url: faker.internet.url() + } +]; + +<Supplementary + value={value} + uploadFile={file => new XMLHttpRequest()}/> +``` diff --git a/src/molecules/Upload.js b/src/molecules/Upload.js index 6d24f2bba..8241fa403 100644 --- a/src/molecules/Upload.js +++ b/src/molecules/Upload.js @@ -1,5 +1,4 @@ import React from 'react' -import UploadingFile from '../atoms/UploadingFile' // TODO: retry on error // TODO: make this a HOC for <UploadingFile>? @@ -58,15 +57,10 @@ class Upload extends React.Component { } render () { - const { file } = this.props + const { file, render } = this.props const { progress, error } = this.state - return ( - <UploadingFile - file={file} - progress={progress} - error={error}/> - ) + return render({ file, progress, error }) } } -- GitLab