migrate file and image widgets
This commit is contained in:
parent
e80a407cee
commit
2efd09ba94
@ -4,13 +4,13 @@ import { GitLabBackend } from 'netlify-cms-backend-gitlab';
|
|||||||
import { GitGatewayBackend } from 'netlify-cms-backend-git-gateway';
|
import { GitGatewayBackend } from 'netlify-cms-backend-git-gateway';
|
||||||
import { TestBackend } from 'netlify-cms-backend-test';
|
import { TestBackend } from 'netlify-cms-backend-test';
|
||||||
import { BooleanControl } from 'netlify-cms-widget-boolean';
|
import { BooleanControl } from 'netlify-cms-widget-boolean';
|
||||||
import { StringControl, StringPreview } from 'netlify-cms-widget-string';
|
|
||||||
import { DateControl, DatePreview } from 'netlify-cms-widget-date';
|
import { DateControl, DatePreview } from 'netlify-cms-widget-date';
|
||||||
import { DateTimeControl, DateTimePreview } from 'netlify-cms-widget-datetime';
|
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 { NumberControl, NumberPreview } from 'netlify-cms-widget-number';
|
||||||
// import { TextControl, TextPreview } from 'netlify-cms-widget-text';
|
// 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 { SelectControl, SelectPreview } from 'netlify-cms-widget-select';
|
||||||
// import { MarkdownControl, MarkdownPreview } from 'netlify-cms-widget-markdown';
|
// import { MarkdownControl, MarkdownPreview } from 'netlify-cms-widget-markdown';
|
||||||
// import { ListControl, ListPreview } from 'netlify-cms-widget-list';
|
// import { ListControl, ListPreview } from 'netlify-cms-widget-list';
|
||||||
@ -25,13 +25,13 @@ registerBackend('test-repo', TestBackend);
|
|||||||
registerWidget('boolean', BooleanControl);
|
registerWidget('boolean', BooleanControl);
|
||||||
registerWidget('date', DateControl, DatePreview);
|
registerWidget('date', DateControl, DatePreview);
|
||||||
registerWidget('datetime', DateTimeControl, DateTimePreview);
|
registerWidget('datetime', DateTimeControl, DateTimePreview);
|
||||||
|
registerWidget('file', FileControl, FilePreview);
|
||||||
|
registerWidget('image', ImageControl, ImagePreview);
|
||||||
registerWidget('string', StringControl, StringPreview);
|
registerWidget('string', StringControl, StringPreview);
|
||||||
// registerWidget('text', TextControl, TextPreview);
|
// registerWidget('text', TextControl, TextPreview);
|
||||||
// registerWidget('number', NumberControl, NumberPreview);
|
// registerWidget('number', NumberControl, NumberPreview);
|
||||||
// registerWidget('list', ListControl, ListPreview);
|
// registerWidget('list', ListControl, ListPreview);
|
||||||
// registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
// registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
||||||
// registerWidget('image', ImageControl, ImagePreview);
|
|
||||||
// registerWidget('file', FileControl, FilePreview);
|
|
||||||
// registerWidget('select', SelectControl, SelectPreview);
|
// registerWidget('select', SelectControl, SelectPreview);
|
||||||
// registerWidget('object', ObjectControl, ObjectPreview);
|
// registerWidget('object', ObjectControl, ObjectPreview);
|
||||||
// registerWidget('relation', RelationControl, RelationPreview);
|
// registerWidget('relation', RelationControl, RelationPreview);
|
||||||
|
@ -5,10 +5,6 @@ import NumberControl from './Number/NumberControl';
|
|||||||
import NumberPreview from './Number/NumberPreview';
|
import NumberPreview from './Number/NumberPreview';
|
||||||
import TextControl from './Text/TextControl';
|
import TextControl from './Text/TextControl';
|
||||||
import TextPreview from './Text/TextPreview';
|
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 SelectControl from './Select/SelectControl';
|
||||||
import SelectPreview from './Select/SelectPreview';
|
import SelectPreview from './Select/SelectPreview';
|
||||||
import MarkdownControl from './Markdown/MarkdownControl';
|
import MarkdownControl from './Markdown/MarkdownControl';
|
||||||
@ -24,8 +20,6 @@ registerWidget('text', TextControl, TextPreview);
|
|||||||
registerWidget('number', NumberControl, NumberPreview);
|
registerWidget('number', NumberControl, NumberPreview);
|
||||||
registerWidget('list', ListControl, ListPreview);
|
registerWidget('list', ListControl, ListPreview);
|
||||||
registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
||||||
registerWidget('image', ImageControl, ImagePreview);
|
|
||||||
registerWidget('file', FileControl, FilePreview);
|
|
||||||
registerWidget('select', SelectControl, SelectPreview);
|
registerWidget('select', SelectControl, SelectPreview);
|
||||||
registerWidget('object', ObjectControl, ObjectPreview);
|
registerWidget('object', ObjectControl, ObjectPreview);
|
||||||
registerWidget('relation', RelationControl, RelationPreview);
|
registerWidget('relation', RelationControl, RelationPreview);
|
||||||
|
@ -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) {
|
export function stringToRGB(str) {
|
||||||
if (!str) return "000000";
|
if (!str) return "000000";
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
|
@ -214,10 +214,15 @@ const components = {
|
|||||||
border-top: 6px solid currentColor;
|
border-top: 6px solid currentColor;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
`,
|
`,
|
||||||
|
textBadge: css`
|
||||||
|
${textBadge};
|
||||||
|
color: ${colors.infoText};
|
||||||
|
background-color: ${colors.infoBackground};
|
||||||
|
`,
|
||||||
textBadgeSuccess: css`
|
textBadgeSuccess: css`
|
||||||
${textBadge};
|
${textBadge};
|
||||||
color: ${colorsRaw.green};
|
color: ${colors.successText};
|
||||||
background-color: ${colorsRaw.greenLight};
|
background-color: ${colors.successBackground};
|
||||||
`,
|
`,
|
||||||
textBadgeDanger: css`
|
textBadgeDanger: css`
|
||||||
${textBadge};
|
${textBadge};
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
export DateTimeControl from './DateTimeControl';
|
export DateTimeControl from './DateTimeControl';
|
||||||
export DateTimePreview from 'netlify-cms-widget-date';
|
export { DatePreview as DateTimePreview } from 'netlify-cms-widget-date';
|
||||||
|
34
packages/netlify-cms-widget-file/package.json
Normal file
34
packages/netlify-cms-widget-file/package.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
16
packages/netlify-cms-widget-file/src/FilePreview.js
Normal file
16
packages/netlify-cms-widget-file/src/FilePreview.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { WidgetPreviewContainer } from 'netlify-cms-ui-default';
|
||||||
|
|
||||||
|
const FilePreview = ({ value, getAsset }) => (
|
||||||
|
<WidgetPreviewContainer>
|
||||||
|
{ value ? <a href={getAsset(value)}>{ value }</a> : null}
|
||||||
|
</WidgetPreviewContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
FilePreview.propTypes = {
|
||||||
|
getAsset: PropTypes.func.isRequired,
|
||||||
|
value: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FilePreview;
|
5
packages/netlify-cms-widget-file/src/index.js
Normal file
5
packages/netlify-cms-widget-file/src/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import withFileControl from './withFileControl';
|
||||||
|
|
||||||
|
export { withFileControl };
|
||||||
|
export const FileControl = withFileControl();
|
||||||
|
export FilePreview from './FilePreview';
|
167
packages/netlify-cms-widget-file/src/withFileControl.js
Normal file
167
packages/netlify-cms-widget-file/src/withFileControl.js
Normal file
@ -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 (
|
||||||
|
<FileContent>
|
||||||
|
{ forImage ? <ImageWrapper><Image src={getAsset(value)}/></ImageWrapper> : null }
|
||||||
|
<FileInfo>
|
||||||
|
<FileName>{fileName}</FileName>
|
||||||
|
<FileWidgetButton onClick={this.handleChange}>
|
||||||
|
Choose different {subject}
|
||||||
|
</FileWidgetButton>
|
||||||
|
<FileWidgetButtonRemove onClick={this.handleRemove}>
|
||||||
|
Remove {subject}
|
||||||
|
</FileWidgetButtonRemove>
|
||||||
|
</FileInfo>
|
||||||
|
</FileContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderNoSelection = (subject, article) => (
|
||||||
|
<FileWidgetButton onClick={this.handleChange}>
|
||||||
|
Choose {article} {subject}
|
||||||
|
</FileWidgetButton>
|
||||||
|
);
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { value, classNameWrapper } = this.props;
|
||||||
|
const subject = forImage ? 'image' : 'file';
|
||||||
|
const article = forImage ? 'an' : 'a';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNameWrapper}>
|
||||||
|
<span>
|
||||||
|
{ value ? this.renderSelection(subject) : this.renderNoSelection(subject, article) }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
3
packages/netlify-cms-widget-file/webpack.config.js
Normal file
3
packages/netlify-cms-widget-file/webpack.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const { getConfig } = require('../../scripts/webpack.js');
|
||||||
|
|
||||||
|
module.exports = getConfig();
|
36
packages/netlify-cms-widget-image/package.json
Normal file
36
packages/netlify-cms-widget-image/package.json
Normal file
@ -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"
|
||||||
|
]
|
||||||
|
}
|
22
packages/netlify-cms-widget-image/src/ImagePreview.js
Normal file
22
packages/netlify-cms-widget-image/src/ImagePreview.js
Normal file
@ -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 }) => (
|
||||||
|
<WidgetPreviewContainer>
|
||||||
|
{ value ? <Image src={getAsset(value)} role="presentation"/> : null}
|
||||||
|
</WidgetPreviewContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
ImagePreview.propTypes = {
|
||||||
|
getAsset: PropTypes.func.isRequired,
|
||||||
|
value: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImagePreview;
|
4
packages/netlify-cms-widget-image/src/index.js
Normal file
4
packages/netlify-cms-widget-image/src/index.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { withFileControl } from 'netlify-cms-widget-file';
|
||||||
|
|
||||||
|
export const ImageControl = withFileControl({ forImage: true });
|
||||||
|
export ImagePreview from './ImagePreview';
|
3
packages/netlify-cms-widget-image/webpack.config.js
Normal file
3
packages/netlify-cms-widget-image/webpack.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const { getConfig } = require('../../scripts/webpack.js');
|
||||||
|
|
||||||
|
module.exports = getConfig();
|
Loading…
x
Reference in New Issue
Block a user