Open kevinfoerster opened 7 years ago
You could create a custom widget that provides a select input for selecting type, and the type definitions could be an array of objects defined in the widget config. Then you just swap in fields based on the selected type.
So I've been considering how this might look. We're now focusing heavily on the extensibility story around the CMS, and a big part of that is making widget authoring simpler, and the available API's more robust.
For this particular issue, we should have a widget as I mentioned in my last comment, but I want it to just be a button with configurable text. In the OP case you would configure the label to "Add content", and it's appearance would simply be that of a dropdown, which editors can use to add one of the widgets configured in the "fields" array. The UI around this could be further enhanced by passing control of labels (optionally) to widget authors (currently all widgets automatically receive a label in the UI direct through the CMS). This means an entry could consist of nothing more than this widget and be entirely dynamic, very similar to what ACF provides to WordPress users.
Furthermore, if the added widgets are themselves draggable, we'd have all that's needed for site building. Doing all of this in a widget is pretty compelling.
Thoughts?
@erquhart thanks for reminding me about this, I have been meaning to get it finished.
Anyhow, I did manage to find a solution to an extent, I could only get preview to work through a custom preview layout. Anyhow, here are some snippets that I generated:
config.yml
- name: slides
label: Slides
widget: list
required: false
fields:
- label: "Slide"
name: "slide"
widget: "dynamic"
dynamicWidgets:
- string
- image
- file
Control
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { Map } from 'immutable';
import CMS from 'netlify-cms';
export default class DynamicControl extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onAddAsset: PropTypes.func.isRequired,
onRemoveAsset: PropTypes.func.isRequired,
getAsset: PropTypes.func.isRequired,
value: PropTypes.oneOfType([
PropTypes.node,
PropTypes.object,
PropTypes.bool,
]),
field: PropTypes.object,
forID: PropTypes.string,
dynamicWidgets: PropTypes.object
};
constructor(props) {
super(props);
const fieldValue = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(this.props.field.get('name')) :
'';
if (!fieldValue) {
this.state = {
widget: null,
};
} else {
this.state = {
widget: CMS.getWidget(fieldValue),
};
}
}
handleChange = (e) => {
this.props.onChange(Map().set(e.target.id, e.target.value));
if (!e.target.value) {
this.setState({
widget: null,
});
} else {
this.setState({
widget: CMS.getWidget(e.target.value),
});
}
};
render() {
const { field, value, forID, onChange, onAddAsset, onRemoveAsset, getAsset } = this.props;
const { widget } = this.state;
const name = field.get('name');
const selectedName = `${ field.get('name') }_selected`;
const fieldValue = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(name || '') :
'';
const fieldValueSelected = this.props.value && Map.isMap(this.props.value) ?
this.props.value.get(selectedName || '') :
'';
let options = field.get('dynamicWidgets').map((option) => {
if (typeof option === 'string') {
return { label: option, value: option };
}
return option;
});
options = options.insert(0, {
label: 'Please Select',
value: '',
});
return (
<div>
<div>
<select id={forID} value={fieldValue || ''} onChange={this.handleChange}>
{options.map((option, idx) => <option key={idx} value={option.value}>
{option.label}
</option>)}
</select>
</div>
<div>
{
widget ?
<div key={selectedName}>
<div key={selectedName}>
<label htmlFor={selectedName}>{`${ field.get('label') } Data`}</label>
{
React.createElement(widget.control, {
id: selectedName,
field,
value: fieldValueSelected,
onChange: (val, metadata) => {
onChange((value || Map()).set(selectedName, val), metadata);
},
onAddAsset,
onRemoveAsset,
getAsset,
forID: selectedName,
})
}
</div>
</div>
:
''
}
</div>
</div>
);
}
}
Hope that helps kick start this conversation ;)
@domtalbot can you open a "WIP" PR with a working implementation?
Hi Shawn,
I should be able to do this over the christmas period yes, will keep this thread updated :)
On 19 December 2017 at 21:48, Shawn Erquhart notifications@github.com wrote:
@domtalbot https://github.com/domtalbot can you open a "WIP" PR with a working implementation?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/netlify/netlify-cms/issues/565#issuecomment-352896609, or mute the thread https://github.com/notifications/unsubscribe-auth/AG11467bYwSm0kzYwWEBDGURYYZlLx5Lks5tCC9LgaJpZM4PGGOv .
--
Kind Regards
Dominic Talbot 07791193905
Started another issue similar to this. Wondering if you got anywhere @domtalbot and if you need any help? #1066
While considering #2405 I think I found a way to statically configure conditional fields right in the yaml while still providing flexibility. Using the original case from @kevinfoerster's OP:
- label: structure
name: structure
widget: list
fields:
- label: type
name: type
widget: select
options:
- copy
- divider
- image
- infographic
- productCircle
- quote
- label: content
name: content
widget: object
fields:
- label: text
name: text
widget: markdown
condition: {type: fieldValue, field: type, oneOf: [copy, productCircle, quote]}
- label: src
name: src
widget: image
condition: {type: fieldValue, field: type, oneOf: [image, infographic, productCircle]}
- label: overlay
name: overlay
widget: image
condition: {type: fieldValue, field: type, equals: infographic}
fieldValue
is just one potential type, and each type can accept different properties, here we use equals
and oneOf
.
condition
could accept either an object or an array. The example above is shorthand for condition.oneOf
, which accepts an object or array of objects, and can be used if condition
itself can be configured with other properties for more control, or alternatives to condition.oneOf
, such as condition.allOf
, which would require all condition objects in an array to validate.
I love this idea of the condition
property suggested above ☝️ Do we have any forward progression on this? Just ran into a couple of scenarios where this would be very helpful. Thanks in advance.
Looks great already @erquhart. Maybe add condition.not
to the list of conditions
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Any updates on this? I want to display a datetime widget only if a boolean widget is false.
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Like give it a thumbs up?
Hi @caseykey, we're working our way through the most upvoted issues first, so best way to push something forward is to upvote it.
Like give it a thumbs up?
Exactly
@erezrokah Where is this on the roadmap? Would be great to get this feature added! I've got a situation that looks like this:
It's very confusing for content editors and hinders their productivity and the potential flexibility of NetlifyCMS.
Thanks to all for your hard work on this project !
Kyle
Hi @kylekirkby, see my comment https://github.com/netlify/netlify-cms/issues/565#issuecomment-576140240 and the most upvoted features here https://github.com/netlify/netlify-cms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc. I think one could implement this in a custom widget, and if that works well we can import it into the main repo.
I managed to get it working as a custom widget for my client site so is perfectly doable. I don't have access to the code anymore though :(
On Mon, 11 May 2020, 11:29 Erez Rokah, notifications@github.com wrote:
Hi @kylekirkby https://github.com/kylekirkby, see my comment #565 (comment) https://github.com/netlify/netlify-cms/issues/565#issuecomment-576140240 and the most upvoted features here https://github.com/netlify/netlify-cms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc . I think one could implement this in a custom widget, and if that works well we can import it into the main repo.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/netlify/netlify-cms/issues/565#issuecomment-626618054, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABWXLY65G5PJCLFOZAPCOHLRQ7HQPANCNFSM4DYYMOXQ .
Hi guys, I would love to see this feature added too. I have a requirement for a page builder. The way I would like it to work would be that you create a new page based on the following in your config.yml:
collections:
- name: 'pages'
label: 'Pages'
label_singular: 'Page'
folder: 'src/_pages/pages'
create: true
identifier_field: name
fields:
- {
label: 'Page Template',
name: 'templateKey',
widget: 'select',
default: 'standardPage',
options:
[
{ label: 'Standard Layout', value: 'standardPage' },
{ label: 'Background Layout', value: 'backgroundPage' },
{ label: 'Carousel Layout', value: 'carouselPage' },
{ label: 'Gallery Layout', value: 'galleryPage' },
],
}
The relevant fields for each type of Layout would be rendered out in the editor panel depending on which dropdown option you selected. Although, I'm not sure how I would associate each dropdown value with a unique set of fields (is this where the beta Variable Types widget comes in to play?) When I publish the page, the page's markdown would just include the frontmatter fields that correspond to the selected layout template (e.g a columns field) that was selected during page creation - all pre-populated of course:
---
templateKey: standardPage
title: Page Title
columns:
columnOne: Column One Text
columnTwo: Column Two Text
columnThree: Column Three Text
---
Hi, any updates on this?
Hi, I need this feature for a client requirement, how is going on?
Hi @filipburian and @miguelt1, we have some in progress work in https://github.com/netlify/netlify-cms/pull/3891 if you'd like to pick it up.
6 years and multiple solutions proposed and still nothing🥲
In my case, I just needed a boolean widget that is attached to a list widget, and boolean widget can show/hide the list. you can use a custom widget similar to this:
// custom widget
import React, { Component } from "react"
import CMS from "netlify-cms-app"
import _ from "lodash"
import { List } from "immutable"
const booleanWidget = CMS.getWidget("boolean")
const listWidget = CMS.getWidget("list")
export class ToggleListControl extends Component {
constructor(props) {
super(props)
this.state = {
show: !_.isNil(this.props.value),
}
}
render() {
const {
value,
forID,
onChange,
classNameWrapper,
setActiveStyle,
setInactiveStyle,
} = this.props
return (
<div>
<div>
{React.createElement(booleanWidget.control, {
value: !_.isNil(value),
onChange: () => {
if (!_.isNil(value)) {
this.setState({ show: false })
onChange(undefined)
} else {
this.setState({ show: true })
onChange(List())
}
},
forID: `${forID}-toggle`,
classNameWrapper,
setActiveStyle,
setInactiveStyle,
})}
</div>
<div style={{ marginTop: "16px" }}>
{!_.isNil(this.props.value) && (
<div>
{React.createElement(listWidget.control, { ...this.props })}
</div>
)}
</div>
</div>
)
}
}
export const ToggleListPreview = ({ value }) => {
return <div></div>
}
and the config would be the same as the one you use for list:
- label: Toggle List
name: fieldname
widget: toggleList
required: false
field: { label: Text, name: text, widget: string }
hey,
i could not find any information about this therefor i thought i would ask here.
is it possible to show and hide fields depending on some other field?
eg. this is my frontmatter
based on that type different configurations for this list item might be needed
eg. if my type is
image
only aimage
field is necessary but if the type isinfographic
and additional overlayimage
can be addedmy
config.yml
looks like thisthis list has a lot of unused options and i am far from done adding all the fields
what would a good way to implement this kind of structure?
cms version 0.4.6