diff --git a/src/atoms/Attachment.js b/src/atoms/Attachment.js new file mode 100644 index 0000000000000000000000000000000000000000..8aa508d41ec566a62eb7a85f0c57081c7d5ce099 --- /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 0000000000000000000000000000000000000000..86fc8df67507122a21e8339480bf120e3d5411de --- /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 0000000000000000000000000000000000000000..3156671c60e5ad5582b67a7a9c8e51471750767f --- /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 975470d80a3b1881118de3032427132f208497b3..4eca93ba0063d5827a56c45719243b6567e95606 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 3ed466791fd6a5260b421a4132e3d3ed9c02f49c..402dfcebe67cda2d2be143bb743ce7ab3eb6f22f 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 0000000000000000000000000000000000000000..445ec1af6caa5bd4d20a43c299eaaf0767702f4a --- /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 0000000000000000000000000000000000000000..49bf286103c840a195a093bd43bb386a62385bfa --- /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 0000000000000000000000000000000000000000..01dbde245a9731b110829726f65d2ad3a928c44f --- /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 e6dc89f78260cdb99adc6bd98d6388c0613de9e4..cc5291619a7bede9768c811b438b535888c5861a 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 568f26f6f852f6b5d70e79c877b9dac4154bb03b..0042861aa9d38170f8ce97ae178ea0c2cd7b0552 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 0000000000000000000000000000000000000000..6095f48baca6b5cf1e4faa949bbb06c201e03527 --- /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 0000000000000000000000000000000000000000..c95a11fb4ef2b02637b55caebb0463ab8b451126 --- /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 6d24f2bba0dbe49b8ddfe7fb92f457ca6170d7d2..8241fa4038f5286da249b9fa2d7288e6878de951 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 }) } }