From 2efd09ba9485b828f0d88e5e06917222b6331ca8 Mon Sep 17 00:00:00 2001 From: Shawn Erquhart Date: Tue, 24 Jul 2018 13:57:57 -0400 Subject: [PATCH] migrate file and image widgets --- .../scripts/load-extensions.js | 10 +- .../src/components/EditorWidgets/index.js | 6 - .../netlify-cms-core/src/lib/textHelper.js | 7 - packages/netlify-cms-ui-default/src/styles.js | 9 +- .../netlify-cms-widget-datetime/src/index.js | 2 +- packages/netlify-cms-widget-file/package.json | 34 ++++ .../src/FilePreview.js | 16 ++ packages/netlify-cms-widget-file/src/index.js | 5 + .../src/withFileControl.js | 167 ++++++++++++++++++ .../netlify-cms-widget-file/webpack.config.js | 3 + .../netlify-cms-widget-image/package.json | 36 ++++ .../src/ImagePreview.js | 22 +++ .../netlify-cms-widget-image/src/index.js | 4 + .../webpack.config.js | 3 + 14 files changed, 303 insertions(+), 21 deletions(-) create mode 100644 packages/netlify-cms-widget-file/package.json create mode 100644 packages/netlify-cms-widget-file/src/FilePreview.js create mode 100644 packages/netlify-cms-widget-file/src/index.js create mode 100644 packages/netlify-cms-widget-file/src/withFileControl.js create mode 100644 packages/netlify-cms-widget-file/webpack.config.js create mode 100644 packages/netlify-cms-widget-image/package.json create mode 100644 packages/netlify-cms-widget-image/src/ImagePreview.js create mode 100644 packages/netlify-cms-widget-image/src/index.js create mode 100644 packages/netlify-cms-widget-image/webpack.config.js diff --git a/packages/netlify-cms-core/scripts/load-extensions.js b/packages/netlify-cms-core/scripts/load-extensions.js index 7f15dda4..f711c78a 100644 --- a/packages/netlify-cms-core/scripts/load-extensions.js +++ b/packages/netlify-cms-core/scripts/load-extensions.js @@ -4,13 +4,13 @@ import { GitLabBackend } from 'netlify-cms-backend-gitlab'; import { GitGatewayBackend } from 'netlify-cms-backend-git-gateway'; import { TestBackend } from 'netlify-cms-backend-test'; import { BooleanControl } from 'netlify-cms-widget-boolean'; -import { StringControl, StringPreview } from 'netlify-cms-widget-string'; import { DateControl, DatePreview } from 'netlify-cms-widget-date'; import { DateTimeControl, DateTimePreview } from 'netlify-cms-widget-datetime'; +import { FileControl, FilePreview } from 'netlify-cms-widget-file'; +import { ImageControl, ImagePreview } from 'netlify-cms-widget-image'; +import { StringControl, StringPreview } from 'netlify-cms-widget-string'; // import { NumberControl, NumberPreview } from 'netlify-cms-widget-number'; // import { TextControl, TextPreview } from 'netlify-cms-widget-text'; -// import { ImageControl, ImagePreview } from 'netlify-cms-widget-image'; -// import { FileControl, FilePreview } from 'netlify-cms-widget-file'; // import { SelectControl, SelectPreview } from 'netlify-cms-widget-select'; // import { MarkdownControl, MarkdownPreview } from 'netlify-cms-widget-markdown'; // import { ListControl, ListPreview } from 'netlify-cms-widget-list'; @@ -25,13 +25,13 @@ registerBackend('test-repo', TestBackend); registerWidget('boolean', BooleanControl); registerWidget('date', DateControl, DatePreview); registerWidget('datetime', DateTimeControl, DateTimePreview); +registerWidget('file', FileControl, FilePreview); +registerWidget('image', ImageControl, ImagePreview); registerWidget('string', StringControl, StringPreview); // registerWidget('text', TextControl, TextPreview); // registerWidget('number', NumberControl, NumberPreview); // registerWidget('list', ListControl, ListPreview); // registerWidget('markdown', MarkdownControl, MarkdownPreview); -// registerWidget('image', ImageControl, ImagePreview); -// registerWidget('file', FileControl, FilePreview); // registerWidget('select', SelectControl, SelectPreview); // registerWidget('object', ObjectControl, ObjectPreview); // registerWidget('relation', RelationControl, RelationPreview); diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/index.js b/packages/netlify-cms-core/src/components/EditorWidgets/index.js index 823275a2..dade5aa3 100644 --- a/packages/netlify-cms-core/src/components/EditorWidgets/index.js +++ b/packages/netlify-cms-core/src/components/EditorWidgets/index.js @@ -5,10 +5,6 @@ import NumberControl from './Number/NumberControl'; import NumberPreview from './Number/NumberPreview'; import TextControl from './Text/TextControl'; import TextPreview from './Text/TextPreview'; -import ImageControl from './Image/ImageControl'; -import ImagePreview from './Image/ImagePreview'; -import FileControl from './File/FileControl'; -import FilePreview from './File/FilePreview'; import SelectControl from './Select/SelectControl'; import SelectPreview from './Select/SelectPreview'; import MarkdownControl from './Markdown/MarkdownControl'; @@ -24,8 +20,6 @@ registerWidget('text', TextControl, TextPreview); registerWidget('number', NumberControl, NumberPreview); registerWidget('list', ListControl, ListPreview); registerWidget('markdown', MarkdownControl, MarkdownPreview); -registerWidget('image', ImageControl, ImagePreview); -registerWidget('file', FileControl, FilePreview); registerWidget('select', SelectControl, SelectPreview); registerWidget('object', ObjectControl, ObjectPreview); registerWidget('relation', RelationControl, RelationPreview); diff --git a/packages/netlify-cms-core/src/lib/textHelper.js b/packages/netlify-cms-core/src/lib/textHelper.js index 9b4d69e4..07d24ff7 100644 --- a/packages/netlify-cms-core/src/lib/textHelper.js +++ b/packages/netlify-cms-core/src/lib/textHelper.js @@ -1,10 +1,3 @@ -export function truncateMiddle(string = "", size) { - if (string.length <= size) { - return string; - } - return `${ string.substring(0, size / 2) }\u2026${ string.substring(string.length - size / 2 + 1, string.length) }`; -} - export function stringToRGB(str) { if (!str) return "000000"; let hash = 0; diff --git a/packages/netlify-cms-ui-default/src/styles.js b/packages/netlify-cms-ui-default/src/styles.js index 1e11dc00..d2548792 100644 --- a/packages/netlify-cms-ui-default/src/styles.js +++ b/packages/netlify-cms-ui-default/src/styles.js @@ -214,10 +214,15 @@ const components = { border-top: 6px solid currentColor; border-radius: 2px; `, + textBadge: css` + ${textBadge}; + color: ${colors.infoText}; + background-color: ${colors.infoBackground}; + `, textBadgeSuccess: css` ${textBadge}; - color: ${colorsRaw.green}; - background-color: ${colorsRaw.greenLight}; + color: ${colors.successText}; + background-color: ${colors.successBackground}; `, textBadgeDanger: css` ${textBadge}; diff --git a/packages/netlify-cms-widget-datetime/src/index.js b/packages/netlify-cms-widget-datetime/src/index.js index d6750c61..6607d356 100644 --- a/packages/netlify-cms-widget-datetime/src/index.js +++ b/packages/netlify-cms-widget-datetime/src/index.js @@ -1,2 +1,2 @@ export DateTimeControl from './DateTimeControl'; -export DateTimePreview from 'netlify-cms-widget-date'; +export { DatePreview as DateTimePreview } from 'netlify-cms-widget-date'; diff --git a/packages/netlify-cms-widget-file/package.json b/packages/netlify-cms-widget-file/package.json new file mode 100644 index 00000000..01160d75 --- /dev/null +++ b/packages/netlify-cms-widget-file/package.json @@ -0,0 +1,34 @@ +{ + "name": "netlify-cms-widget-file", + "description": "Widget for uploading files in Netlify CMS.", + "version": "2.0.0-alpha.0", + "main": "dist/netlify-cms-widget-file.js", + "license": "MIT", + "keywords": [ + "netlify", + "netlify-cms", + "widget", + "file", + "upload", + "file-upload" + ], + "sideEffects": false, + "scripts": { + "watch": "webpack -w", + "build": "webpack" + }, + "dependencies": { + "uuid": "^3.3.2" + }, + "devDependencies": { + "webpack": "^4.16.1", + "webpack-cli": "^3.1.0" + }, + "peerDependencies": { + "netlify-cms-ui-default": "^2.0.0-alpha.0", + "prop-types": "^15.5.10", + "react": "^16.4.1", + "react-emotion": "^9.2.6", + "react-immutable-proptypes": "^2.1.0" + } +} diff --git a/packages/netlify-cms-widget-file/src/FilePreview.js b/packages/netlify-cms-widget-file/src/FilePreview.js new file mode 100644 index 00000000..c2c2743f --- /dev/null +++ b/packages/netlify-cms-widget-file/src/FilePreview.js @@ -0,0 +1,16 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; + +const FilePreview = ({ value, getAsset }) => ( + + { value ? { value } : null} + +); + +FilePreview.propTypes = { + getAsset: PropTypes.func.isRequired, + value: PropTypes.node, +}; + +export default FilePreview; diff --git a/packages/netlify-cms-widget-file/src/index.js b/packages/netlify-cms-widget-file/src/index.js new file mode 100644 index 00000000..68141579 --- /dev/null +++ b/packages/netlify-cms-widget-file/src/index.js @@ -0,0 +1,5 @@ +import withFileControl from './withFileControl'; + +export { withFileControl }; +export const FileControl = withFileControl(); +export FilePreview from './FilePreview'; diff --git a/packages/netlify-cms-widget-file/src/withFileControl.js b/packages/netlify-cms-widget-file/src/withFileControl.js new file mode 100644 index 00000000..91455f47 --- /dev/null +++ b/packages/netlify-cms-widget-file/src/withFileControl.js @@ -0,0 +1,167 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import styled from 'react-emotion'; +import uuid from 'uuid/v4'; +import { lengths, components, buttons } from 'netlify-cms-ui-default'; + +const MAX_DISPLAY_LENGTH = 50; + +const FileContent = styled.div` + display: flex; +` + +const ImageWrapper = styled.div` + width: 155px; + height: 100px; + margin-right: 20px; +` + +const Image = styled.img` + width: 100%; + height: 100%; + object-fit: cover; + border-radius: ${lengths.borderRadius}; +` + +const FileInfo = styled.div` + button:not(:first-child) { + margin-top: 12px; + } +` + +const FileName = styled.span` + display: block; + font-size: 16px; + margin-bottom: 20px; +` + +const FileWidgetButton = styled.button` + ${buttons.button}; + ${components.textBadge}; + display: block; +` + +const FileWidgetButtonRemove = styled.button` + ${buttons.button}; + ${components.textBadgeDanger}; + display: block; +` + +export default function withFileControl({ forImage } = {}) { + return class extends React.Component { + static propTypes = { + field: PropTypes.object.isRequired, + getAsset: PropTypes.func.isRequired, + mediaPaths: ImmutablePropTypes.map.isRequired, + onAddAsset: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + onRemoveInsertedMedia: PropTypes.func.isRequired, + onOpenMediaLibrary: PropTypes.func.isRequired, + classNameWrapper: PropTypes.string.isRequired, + value: PropTypes.node, + }; + + static defaultProps = { + value: '', + }; + + constructor(props) { + super(props); + this.controlID = uuid(); + } + + shouldComponentUpdate(nextProps) { + /** + * Always update if the value changes. + */ + if (this.props.value !== nextProps.value) { + return true; + } + + /** + * If there is a media path for this control in the state object, and that + * path is different than the value in `nextProps`, update. + */ + const mediaPath = nextProps.mediaPaths.get(this.controlID); + if (mediaPath && (nextProps.value !== mediaPath)) { + return true; + } + + return false; + } + + componentWillReceiveProps(nextProps) { + const { mediaPaths, value, onRemoveInsertedMedia, onChange } = nextProps; + const mediaPath = mediaPaths.get(this.controlID); + if (mediaPath && mediaPath !== value) { + onChange(mediaPath); + } else if (mediaPath && mediaPath === value) { + onRemoveInsertedMedia(this.controlID); + } + } + + handleChange = e => { + const { field, onOpenMediaLibrary } = this.props; + e.preventDefault(); + return onOpenMediaLibrary({ + controlID: this.controlID, + forImage, + privateUpload: field.get('private'), + }); + }; + + handleRemove = e => { + e.preventDefault(); + return this.props.onChange(''); + }; + + renderFileName = () => { + const { value, classNameWrapper } = this.props; + const size = MAX_DISPLAY_LENGTH; + if (!value || value.length <= size) { + return value; + } + return `${ value.substring(0, size / 2) }\u2026${ value.substring(value.length - size / 2 + 1, value.length) }`; + }; + + renderSelection = (subject) => { + const fileName = this.renderFileName(); + const { getAsset, value } = this.props; + return ( + + { forImage ? : null } + + {fileName} + + Choose different {subject} + + + Remove {subject} + + + + ); + }; + + renderNoSelection = (subject, article) => ( + + Choose {article} {subject} + + ); + + render() { + const { value, classNameWrapper } = this.props; + const subject = forImage ? 'image' : 'file'; + const article = forImage ? 'an' : 'a'; + + return ( +
+ + { value ? this.renderSelection(subject) : this.renderNoSelection(subject, article) } + +
+ ); + } + } +}; diff --git a/packages/netlify-cms-widget-file/webpack.config.js b/packages/netlify-cms-widget-file/webpack.config.js new file mode 100644 index 00000000..42edd361 --- /dev/null +++ b/packages/netlify-cms-widget-file/webpack.config.js @@ -0,0 +1,3 @@ +const { getConfig } = require('../../scripts/webpack.js'); + +module.exports = getConfig(); diff --git a/packages/netlify-cms-widget-image/package.json b/packages/netlify-cms-widget-image/package.json new file mode 100644 index 00000000..63442799 --- /dev/null +++ b/packages/netlify-cms-widget-image/package.json @@ -0,0 +1,36 @@ +{ + "name": "netlify-cms-widget-image", + "description": "Widget for uploading images in Netlify CMS.", + "version": "2.0.0-alpha.0", + "main": "dist/netlify-cms-widget-image.js", + "license": "MIT", + "keywords": [ + "netlify", + "netlify-cms", + "widget", + "image", + "upload", + "image-upload" + ], + "sideEffects": false, + "scripts": { + "watch": "webpack -w", + "build": "webpack" + }, + "dependencies": { + "netlify-cms-widget-file": "^2.0.0-alpha.0" + }, + "devDependencies": { + "webpack": "^4.16.1", + "webpack-cli": "^3.1.0" + }, + "peerDependencies": { + "netlify-cms-ui-default": "^2.0.0-alpha.0", + "prop-types": "^15.5.10", + "react": "^16.4.1", + "react-emotion": "^9.2.6" + }, + "localExternals": [ + "netlify-cms-widget-file" + ] +} diff --git a/packages/netlify-cms-widget-image/src/ImagePreview.js b/packages/netlify-cms-widget-image/src/ImagePreview.js new file mode 100644 index 00000000..f588f47d --- /dev/null +++ b/packages/netlify-cms-widget-image/src/ImagePreview.js @@ -0,0 +1,22 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'react-emotion'; +import { WidgetPreviewContainer } from 'netlify-cms-ui-default'; + +const Image = styled.img` + max-width: 100%; + height: auto; +` + +const ImagePreview = ({ value, getAsset }) => ( + + { value ? : null} + +); + +ImagePreview.propTypes = { + getAsset: PropTypes.func.isRequired, + value: PropTypes.node, +}; + +export default ImagePreview; diff --git a/packages/netlify-cms-widget-image/src/index.js b/packages/netlify-cms-widget-image/src/index.js new file mode 100644 index 00000000..b437a158 --- /dev/null +++ b/packages/netlify-cms-widget-image/src/index.js @@ -0,0 +1,4 @@ +import { withFileControl } from 'netlify-cms-widget-file'; + +export const ImageControl = withFileControl({ forImage: true }); +export ImagePreview from './ImagePreview'; diff --git a/packages/netlify-cms-widget-image/webpack.config.js b/packages/netlify-cms-widget-image/webpack.config.js new file mode 100644 index 00000000..42edd361 --- /dev/null +++ b/packages/netlify-cms-widget-image/webpack.config.js @@ -0,0 +1,3 @@ +const { getConfig } = require('../../scripts/webpack.js'); + +module.exports = getConfig();