From 329c8e27d1c6855e5c16587356cf3b4a736e7420 Mon Sep 17 00:00:00 2001 From: Alin Voinea Date: Wed, 12 Aug 2020 16:14:54 +0300 Subject: [PATCH] Add File and Image Widgets --- src/components/index.js | 2 + src/components/theme/Widgets/FileWidget.jsx | 39 ++++++++++++++++ .../theme/Widgets/FileWidget.test.js | 45 +++++++++++++++++++ src/components/theme/Widgets/ImageWidget.jsx | 31 +++++++++++++ .../theme/Widgets/ImageWidget.test.js | 35 +++++++++++++++ .../__snapshots__/FileWidget.test.js.snap | 44 ++++++++++++++++++ .../__snapshots__/ImageWidget.test.js.snap | 31 +++++++++++++ src/index.js | 6 +++ 8 files changed, 233 insertions(+) create mode 100644 src/components/theme/Widgets/FileWidget.jsx create mode 100644 src/components/theme/Widgets/FileWidget.test.js create mode 100644 src/components/theme/Widgets/ImageWidget.jsx create mode 100644 src/components/theme/Widgets/ImageWidget.test.js create mode 100644 src/components/theme/Widgets/__snapshots__/FileWidget.test.js.snap create mode 100644 src/components/theme/Widgets/__snapshots__/ImageWidget.test.js.snap diff --git a/src/components/index.js b/src/components/index.js index ff92117..3e6d688 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -7,6 +7,8 @@ export { BooleanWidget } from './theme/Widgets/BooleanWidget'; export { DatetimeWidget } from './theme/Widgets/DatetimeWidget'; export { DateWidget } from './theme/Widgets/DateWidget'; export { EmailWidget } from './theme/Widgets/EmailWidget'; +export { FileWidget } from './theme/Widgets/FileWidget'; +export { ImageWidget } from './theme/Widgets/ImageWidget'; export { PasswordWidget } from './theme/Widgets/PasswordWidget'; export { RelationsWidget } from './theme/Widgets/RelationsWidget'; export { RelationWidget } from './theme/Widgets/RelationWidget'; diff --git a/src/components/theme/Widgets/FileWidget.jsx b/src/components/theme/Widgets/FileWidget.jsx new file mode 100644 index 0000000..4a7295f --- /dev/null +++ b/src/components/theme/Widgets/FileWidget.jsx @@ -0,0 +1,39 @@ +import React from 'react'; +import cx from 'classnames'; +import { flattenToAppURL } from '@plone/volto/helpers'; + +const niceBytes = (bytes) => { + bytes = Number(bytes); + + const divider = 1000; + const magnitude = (Math.log(bytes) / Math.log(divider)) | 0; + const result = bytes / Math.pow(divider, magnitude); + const fixed = result.toFixed(2); + + const suffix = magnitude ? 'kMGTPEZY'[magnitude - 1] + 'B' : 'B'; + + return fixed + suffix; +}; + +export const FileWidget = ({ value, children, className }) => { + if (!value) { + return ''; + } + + const url = flattenToAppURL(value.download || value.filename || value); + const filename = value.filename || url; + const size = value.size || 0; + const ctype = value['content-type'] || ''; + return ( + + {children ? children(filename) : filename} + + ); +}; diff --git a/src/components/theme/Widgets/FileWidget.test.js b/src/components/theme/Widgets/FileWidget.test.js new file mode 100644 index 0000000..12c10aa --- /dev/null +++ b/src/components/theme/Widgets/FileWidget.test.js @@ -0,0 +1,45 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { FileWidget } from './FileWidget'; + +describe('FileWidget', () => { + it('renders an empty file view widget component', () => { + const component = renderer.create(); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders a simple file view widget component', () => { + const component = renderer.create( + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders a file view widget component', () => { + const component = renderer.create( + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders a file view widget component with children', () => { + const component = renderer.create( + + {(child) => {child}} + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); +}); diff --git a/src/components/theme/Widgets/ImageWidget.jsx b/src/components/theme/Widgets/ImageWidget.jsx new file mode 100644 index 0000000..d6d2ad3 --- /dev/null +++ b/src/components/theme/Widgets/ImageWidget.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import cx from 'classnames'; +import { flattenToAppURL } from '@plone/volto/helpers'; + +const niceBytes = (bytes) => { + bytes = Number(bytes); + + const divider = 1000; + const magnitude = (Math.log(bytes) / Math.log(divider)) | 0; + const result = bytes / Math.pow(divider, magnitude); + const fixed = result.toFixed(2); + + const suffix = magnitude ? 'kMGTPEZY'[magnitude - 1] + 'B' : 'B'; + + return fixed + suffix; +}; + +export const ImageWidget = ({ value, className }) => + value ? ( + + {value.file_name + + ) : ( + '' + ); diff --git a/src/components/theme/Widgets/ImageWidget.test.js b/src/components/theme/Widgets/ImageWidget.test.js new file mode 100644 index 0000000..09701d7 --- /dev/null +++ b/src/components/theme/Widgets/ImageWidget.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { ImageWidget } from './ImageWidget'; + +describe('ImageWidget', () => { + it('renders an empty image view widget component', () => { + const component = renderer.create(); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders an image view widget component', () => { + const component = renderer.create( + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); + + it('renders an image view widget component with children', () => { + const component = renderer.create( + + {(child) => {child}} + , + ); + const json = component.toJSON(); + expect(json).toMatchSnapshot(); + }); +}); diff --git a/src/components/theme/Widgets/__snapshots__/FileWidget.test.js.snap b/src/components/theme/Widgets/__snapshots__/FileWidget.test.js.snap new file mode 100644 index 0000000..a572fc0 --- /dev/null +++ b/src/components/theme/Widgets/__snapshots__/FileWidget.test.js.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FileWidget renders a file view widget component 1`] = ` + + /foo-bar.pdf + +`; + +exports[`FileWidget renders a file view widget component with children 1`] = ` + + + foo-bar.pdf + + +`; + +exports[`FileWidget renders a simple file view widget component 1`] = ` + + /foo-bar.pdf + +`; + +exports[`FileWidget renders an empty file view widget component 1`] = `""`; diff --git a/src/components/theme/Widgets/__snapshots__/ImageWidget.test.js.snap b/src/components/theme/Widgets/__snapshots__/ImageWidget.test.js.snap new file mode 100644 index 0000000..96fc65d --- /dev/null +++ b/src/components/theme/Widgets/__snapshots__/ImageWidget.test.js.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ImageWidget renders an empty image view widget component 1`] = `""`; + +exports[`ImageWidget renders an image view widget component 1`] = ` + + + +`; + +exports[`ImageWidget renders an image view widget component with children 1`] = ` + + foo-bar.png + +`; diff --git a/src/index.js b/src/index.js index edbf8cd..474ef45 100644 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,9 @@ import { BooleanWidget } from './components'; import { DatetimeWidget } from './components'; import { DateWidget } from './components'; import { EmailWidget } from './components'; +import { FileWidget } from './components'; import { getWidgetView } from './helpers'; +import { ImageWidget } from './components'; import { PasswordWidget } from './components'; import { RelationsWidget } from './components'; import { RelationWidget } from './components'; @@ -21,6 +23,8 @@ const applyConfig = (config) => { id: { subjects: TokenWidget, relatedItems: RelationsWidget, + image: ImageWidget, + file: FileWidget, }, widget: { array: ArrayWidget, @@ -29,6 +33,8 @@ const applyConfig = (config) => { date: DateWidget, datetime: DatetimeWidget, email: EmailWidget, + file: FileWidget, + image: ImageWidget, password: PasswordWidget, relation: RelationWidget, relations: RelationsWidget,