Single file collections (#132)
* Files based collections skeleton * listing file based cards * create new entry with collection * moved lookupEntry to main backend * Editing single page Collections file * List widget basic implementation * Adjustments for test-repo * check if value exists before trying to iterate over
This commit is contained in:
@ -6,7 +6,7 @@ import styles from './ControlPane.css';
|
||||
export default class ControlPane extends Component {
|
||||
|
||||
controlFor(field) {
|
||||
const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||
const { entry, fields, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||
const widget = resolveWidget(field.get('widget'));
|
||||
const fieldName = field.get('name');
|
||||
const value = entry.getIn(['data', fieldName]);
|
||||
@ -29,23 +29,22 @@ export default class ControlPane extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { collection } = this.props;
|
||||
if (!collection) {
|
||||
const { collection, fields } = this.props;
|
||||
if (!collection || !fields) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
collection
|
||||
.get('fields')
|
||||
.map(field =>
|
||||
<div
|
||||
key={field.get('name')}
|
||||
className={styles.widget}
|
||||
>
|
||||
{this.controlFor(field)}
|
||||
</div>
|
||||
)
|
||||
fields.map(field =>
|
||||
<div
|
||||
key={field.get('name')}
|
||||
className={styles.widget}
|
||||
>
|
||||
{this.controlFor(field)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
@ -55,6 +54,7 @@ export default class ControlPane extends Component {
|
||||
ControlPane.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
onAddMedia: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@ -10,6 +10,7 @@ export default function EntryEditor(
|
||||
{
|
||||
collection,
|
||||
entry,
|
||||
fields,
|
||||
getMedia,
|
||||
onChange,
|
||||
onAddMedia,
|
||||
@ -26,6 +27,7 @@ export default function EntryEditor(
|
||||
<ControlPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
onChange={onChange}
|
||||
onAddMedia={onAddMedia}
|
||||
@ -37,6 +39,7 @@ export default function EntryEditor(
|
||||
<PreviewPane
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
getMedia={getMedia}
|
||||
/>
|
||||
</div>
|
||||
@ -56,6 +59,7 @@ export default function EntryEditor(
|
||||
EntryEditor.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
onAddMedia: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@ -21,7 +21,7 @@ export default class EntryListing extends React.Component {
|
||||
{ mq: '1005px', columns: 4, gutter: 15 },
|
||||
{ mq: '1515px', columns: 5, gutter: 15 },
|
||||
{ mq: '1770px', columns: 6, gutter: 15 },
|
||||
]
|
||||
],
|
||||
};
|
||||
|
||||
this.updateBricks = _.throttle(this.updateBricks.bind(this), 30);
|
||||
@ -32,7 +32,7 @@ export default class EntryListing extends React.Component {
|
||||
this.bricksInstance = Bricks({
|
||||
container: this._entries,
|
||||
packed: this.bricksConfig.packed,
|
||||
sizes: this.bricksConfig.sizes
|
||||
sizes: this.bricksConfig.sizes,
|
||||
});
|
||||
|
||||
this.bricksInstance.resize(true);
|
||||
@ -65,10 +65,10 @@ export default class EntryListing extends React.Component {
|
||||
const card = Cards[cartType] || Cards._unknown;
|
||||
return React.createElement(card, {
|
||||
key: entry.get('slug'),
|
||||
collection: collection,
|
||||
collection,
|
||||
onClick: history.push.bind(this, link),
|
||||
onImageLoaded: this.updateBricks,
|
||||
text: entry.getIn(['data', collection.getIn(['card', 'text'])]),
|
||||
text: entry.get('label') ? entry.get('label') : entry.getIn(['data', collection.getIn(['card', 'text'])]),
|
||||
description: entry.getIn(['data', collection.getIn(['card', 'description'])]),
|
||||
image: entry.getIn(['data', collection.getIn(['card', 'image'])]),
|
||||
});
|
||||
@ -83,13 +83,13 @@ export default class EntryListing extends React.Component {
|
||||
if (Map.isMap(collections)) {
|
||||
const collectionName = collections.get('name');
|
||||
return entries.map((entry) => {
|
||||
const path = `/collections/${collectionName}/entries/${entry.get('slug')}`;
|
||||
const path = `/collections/${ collectionName }/entries/${ entry.get('slug') }`;
|
||||
return this.cardFor(collections, entry, path);
|
||||
});
|
||||
} else {
|
||||
return entries.map((entry) => {
|
||||
const collection = collections.filter(collection => collection.get('name') === entry.get('collection')).first();
|
||||
const path = `/collections/${collection.get('name')}/entries/${entry.get('slug')}`;
|
||||
const path = `/collections/${ collection.get('name') }/entries/${ entry.get('slug') }`;
|
||||
return this.cardFor(collection, entry, path);
|
||||
});
|
||||
}
|
||||
@ -98,13 +98,13 @@ export default class EntryListing extends React.Component {
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const cards = this.renderCards();
|
||||
return <div>
|
||||
return (<div>
|
||||
<h1>{children}</h1>
|
||||
<div ref={(c) => this._entries = c}>
|
||||
<div ref={c => this._entries = c}>
|
||||
{cards}
|
||||
<Waypoint onEnter={this.handleLoadMore} />
|
||||
</div>
|
||||
</div>;
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ EntryListing.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
collections: PropTypes.oneOfType([
|
||||
ImmutablePropTypes.map,
|
||||
ImmutablePropTypes.iterable
|
||||
ImmutablePropTypes.iterable,
|
||||
]).isRequired,
|
||||
entries: ImmutablePropTypes.list,
|
||||
onPaginate: PropTypes.func.isRequired,
|
||||
|
@ -1,14 +1,13 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
export default function Preview({ collection, widgetFor }) {
|
||||
if (!collection) {
|
||||
export default function Preview({ collection, fields, widgetFor }) {
|
||||
if (!collection || !fields) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{collection.get('fields').map(field => widgetFor(field.get('name')))}
|
||||
{fields.map(field => widgetFor(field.get('name')))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -16,6 +15,7 @@ export default function Preview({ collection, widgetFor }) {
|
||||
Preview.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
widgetFor: PropTypes.func.isRequired,
|
||||
};
|
||||
|
@ -14,8 +14,8 @@ export default class PreviewPane extends React.Component {
|
||||
}
|
||||
|
||||
widgetFor = (name) => {
|
||||
const { collection, entry, getMedia } = this.props;
|
||||
const field = collection.get('fields').find(field => field.get('name') === name);
|
||||
const { fields, entry, getMedia } = this.props;
|
||||
const field = fields.find(field => field.get('name') === name);
|
||||
const widget = resolveWidget(field.get('widget'));
|
||||
return React.createElement(widget.preview, {
|
||||
key: field.get('name'),
|
||||
@ -67,6 +67,7 @@ export default class PreviewPane extends React.Component {
|
||||
|
||||
PreviewPane.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
scrollTop: PropTypes.number,
|
||||
|
@ -3,6 +3,8 @@ import UnknownControl from './Widgets/UnknownControl';
|
||||
import UnknownPreview from './Widgets/UnknownPreview';
|
||||
import StringControl from './Widgets/StringControl';
|
||||
import StringPreview from './Widgets/StringPreview';
|
||||
import ListControl from './Widgets/ListControl';
|
||||
import ListPreview from './Widgets/ListPreview';
|
||||
import TextControl from './Widgets/TextControl';
|
||||
import TextPreview from './Widgets/TextPreview';
|
||||
import MarkdownControl from './Widgets/MarkdownControl';
|
||||
@ -14,6 +16,7 @@ import DateTimePreview from './Widgets/DateTimePreview';
|
||||
|
||||
registry.registerWidget('string', StringControl, StringPreview);
|
||||
registry.registerWidget('text', TextControl, TextPreview);
|
||||
registry.registerWidget('list', ListControl, ListPreview);
|
||||
registry.registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
||||
registry.registerWidget('image', ImageControl, ImagePreview);
|
||||
registry.registerWidget('datetime', DateTimeControl, DateTimePreview);
|
||||
|
17
src/components/Widgets/ListControl.js
Normal file
17
src/components/Widgets/ListControl.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
export default class ListControl extends Component {
|
||||
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.node,
|
||||
};
|
||||
handleChange = (e) => {
|
||||
this.props.onChange(e.target.value.split(',').map(item => item.trim()));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value } = this.props;
|
||||
return <input type="text" value={value ? value.join(', ') : ''} onChange={this.handleChange} />;
|
||||
}
|
||||
}
|
11
src/components/Widgets/ListPreview.js
Normal file
11
src/components/Widgets/ListPreview.js
Normal file
@ -0,0 +1,11 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
|
||||
export default function ListPreview({ value }) {
|
||||
return (<ul>
|
||||
{ value && value.map(item => <li key={item}>{item}</li>) }
|
||||
</ul>);
|
||||
}
|
||||
|
||||
ListPreview.propTypes = {
|
||||
value: PropTypes.node,
|
||||
};
|
Reference in New Issue
Block a user