Feature/typescript conversion (#44)
This commit is contained in:
committed by
GitHub
parent
7fe23baf0b
commit
e60e1fa755
@ -5,6 +5,6 @@ author: Daniel Lautzenheiser
|
||||
description: >-
|
||||
Announcing the release of Static CMS v1.0.
|
||||
twitter_image: /img/static-cms.png
|
||||
date: 2022-10-30T12:00:00.000Z
|
||||
date: 2022-11-30T12:00:00.000Z
|
||||
---
|
||||
Today we’re releasing Static CMS 1.0!
|
@ -22,7 +22,7 @@ Entries are loaded and persisted through a `backend` that will typically represe
|
||||
|
||||
**Config:** Holds the environment configuration (backend type, available collections and fields).
|
||||
|
||||
**Collections:** List of available collections, their fields and metadata information.
|
||||
**Collections:** List of available collections and their fields information.
|
||||
|
||||
**Entries:** Entries for each field.
|
||||
|
||||
@ -58,7 +58,7 @@ For either updating an existing entry or creating a new one, the `EntryEditor` i
|
||||
The control component receives one (1) callback as a prop: `onChange`.
|
||||
|
||||
* onChange (required): Should be called when the users changes the current value. It will ultimately end up updating the EntryDraft object in the Redux Store, thus updating the preview component.
|
||||
* onAddAsset & onRemoveAsset (optionals): Should be invoked with an `AssetProxy` value object if the field accepts file uploads for media (images, for example). `onAddAsset` will get the current media stored in the Redux state tree while `onRemoveAsset` will remove it. AssetProxy objects are stored in the `Medias` object and referenced in the `EntryDraft` object on the state tree.
|
||||
* addAsset & onRemoveAsset (optionals): Should be invoked with an `AssetProxy` value object if the field accepts file uploads for media (images, for example). `addAsset` will get the current media stored in the Redux state tree while `onRemoveAsset` will remove it. AssetProxy objects are stored in the `Medias` object and referenced in the `EntryDraft` object on the state tree.
|
||||
|
||||
Both control and preview widgets receive a `getAsset` selector via props. Displaying the media (or its URI) for the user should always be done via `getAsset`, as it returns an AssetProxy that can return the correct value for both medias already persisted on the server and cached media not yet uploaded.
|
||||
|
||||
|
@ -71,7 +71,7 @@ i18n:
|
||||
|
||||
# Optional, defaults to the first item in locales.
|
||||
# The locale to be used for fields validation and as a baseline for the entry.
|
||||
default_locale: en
|
||||
defaultLocale: en
|
||||
```
|
||||
|
||||
### Collection level configuration
|
||||
@ -442,20 +442,6 @@ init({
|
||||
CMS.registerPreviewTemplate(...);
|
||||
```
|
||||
|
||||
## Raw CSS in `registerPreviewStyle`
|
||||
|
||||
`registerPreviewStyle` can now accept a CSS string, in addition to accepting a url. The feature is activated by passing in an object as the second argument, with `raw` set to a truthy value. This is critical for integrating with modern build tooling. Here's an example using webpack:
|
||||
|
||||
```js
|
||||
/**
|
||||
* Assumes a webpack project with `sass-loader` and `css-loader` installed.
|
||||
* Takes advantage of the `toString` method in the return value of `css-loader`.
|
||||
*/
|
||||
import CMS from '@staticcms/core';
|
||||
import styles from '!css-loader!sass-loader!../main.scss';
|
||||
CMS.registerPreviewStyle(styles.toString(), { raw: true });
|
||||
```
|
||||
|
||||
## Commit Message Templates
|
||||
|
||||
You can customize the templates used by Static CMS to generate commit messages by setting the `commit_messages` option under `backend` in your Static CMS `config.yml`.
|
||||
@ -539,7 +525,7 @@ Example usage:
|
||||
```javascript
|
||||
CMS.registerEventListener({
|
||||
name: 'prePublish',
|
||||
handler: ({ author, entry }) => console.info(JSON.stringify({ author, data: entry.get('data') })),
|
||||
handler: ({ author, entry }) => console.info(JSON.stringify({ author, data: entry.data })),
|
||||
});
|
||||
```
|
||||
|
||||
@ -549,7 +535,7 @@ Supported events are `prePublish`, `postPublish`, `preSave` and `postSave`. The
|
||||
CMS.registerEventListener({
|
||||
name: 'preSave',
|
||||
handler: ({ entry }) => {
|
||||
return entry.get('data').set('title', 'new title');
|
||||
return entry.data.set('title', 'new title');
|
||||
},
|
||||
});
|
||||
```
|
||||
@ -613,9 +599,6 @@ collections:
|
||||
- label: Body
|
||||
name: body
|
||||
widget: markdown
|
||||
# adding a meta object with a path property allows editing the path of entries
|
||||
# moving an existing entry will move the entire sub tree of the entry to the new location
|
||||
meta: { path: { widget: string, label: 'Path', index_file: 'index' } }
|
||||
```
|
||||
|
||||
Nested collections expect the following directory structure:
|
||||
|
@ -33,7 +33,7 @@ CMS.registerWidget(name, control, [preview], [schema]);
|
||||
| ----------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | `string` | Widget name, allows this widget to be used via the field `widget` property in config |
|
||||
| `control` | `React.Component` or `string` | <ul><li>React component that renders the control, receives the following props: <ul><li>**value:** Current field value</li><li>**field:** Immutable map of current field configuration</li><li>**forID:** Unique identifier for the field</li><li>**classNameWrapper:** class name to apply CMS styling to the field</li><li>**onChange:** Callback function to update the field value</li></ul></li><li>Name of a registered widget whose control should be used (includes built in widgets).</li></ul> |
|
||||
| [`preview`] | `React.Component`, optional | Renders the widget preview, receives the following props: <ul><li>**value:** Current preview value</li><li>**field:** Immutable map of current field configuration</li><li>**metadata:** Immutable map of any available metadata for the current field</li><li>**getAsset:** Function for retrieving an asset url for image/file fields</li><li>**entry:** Immutable Map of all entry data</li><li>**fieldsMetaData:** Immutable map of metadata from all fields.</li></ul> |
|
||||
| [`preview`] | `React.Component`, optional | Renders the widget preview, receives the following props: <ul><li>**value:** Current preview value</li><li>**field:** Immutable map of current field configuration</li><li>**getAsset:** Function for retrieving an asset url for image/file fields</li><li>**entry:** Immutable Record of all entry data</li></ul> |
|
||||
| [`schema`] | `JSON Schema object`, optional | Enforces a schema for the widget's field configuration |
|
||||
|
||||
**Example:**
|
||||
|
@ -6,50 +6,12 @@ group: Customization
|
||||
|
||||
The Static CMS exposes a `window.CMS` global object that you can use to register custom widgets, previews and editor plugins. The available customization methods are:
|
||||
|
||||
* **registerPreviewStyle:** Register a custom stylesheet to use on the preview pane.
|
||||
* **registerPreviewTemplate:** Registers a template for a collection.
|
||||
- **registerPreviewTemplate:** Registers a template for a collection.
|
||||
|
||||
### React Components inline interaction
|
||||
|
||||
Static CMS is a collection of React components and exposes two constructs globally to allow you to create components inline: ‘createClass’ and ‘h’ (alias for React.createElement).
|
||||
|
||||
## `registerPreviewStyle`
|
||||
|
||||
Register a custom stylesheet to use on the preview pane.
|
||||
|
||||
```js
|
||||
CMS.registerPreviewStyle(file);
|
||||
```
|
||||
|
||||
**Params:**
|
||||
|
||||
* **file:** css file path
|
||||
|
||||
**Example:**
|
||||
|
||||
```html
|
||||
// index.html
|
||||
<script src="https://unpkg.com/@staticcms/core@%5E0.1.0/dist/static-cms-core.js"></script>
|
||||
<script>
|
||||
CMS.registerPreviewStyle("/example.css");
|
||||
</script>
|
||||
```
|
||||
|
||||
```css
|
||||
/* example.css */
|
||||
|
||||
html,
|
||||
body {
|
||||
color: #444;
|
||||
font-size: 14px;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
```
|
||||
|
||||
## `registerPreviewTemplate`
|
||||
|
||||
Registers a template for a folder collection or an individual file in a file collection.
|
||||
@ -58,44 +20,50 @@ Registers a template for a folder collection or an individual file in a file col
|
||||
|
||||
**Params:**
|
||||
|
||||
* name: The name of the collection (or file for file collections) which this preview component will be used for.
|
||||
* Folder collections: Use the name of the collection
|
||||
* File collections: Use the name of the file
|
||||
* react_component: A React component that renders the collection data. Six props will be passed to your component during render:
|
||||
* entry: Immutable collection containing the entry data.
|
||||
* widgetFor: Returns the appropriate widget preview component for a given field.
|
||||
* [widgetsFor](#lists-and-objects): Returns an array of objects with widgets and associated field data. For use with list and object type entries.
|
||||
* getAsset: Returns the correct filePath or in-memory preview for uploaded images.
|
||||
- name: The name of the collection (or file for file collections) which this preview component will be used for.
|
||||
- Folder collections: Use the name of the collection
|
||||
- File collections: Use the name of the file
|
||||
- react_component: A React component that renders the collection data. Six props will be passed to your component during render:
|
||||
|
||||
- entry: Immutable collection containing the entry data.
|
||||
- widgetFor: Returns the appropriate widget preview component for a given field.
|
||||
- [widgetsFor](#lists-and-objects): Returns an array of objects with widgets and associated field data. For use with list and object type entries.
|
||||
- getAsset: Returns the correct filePath or in-memory preview for uploaded images.
|
||||
**Example:**
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@staticcms/core@%5E0.1.0/dist/static-cms-core.js"></script>
|
||||
<script>
|
||||
var PostPreview = createClass({
|
||||
render: function() {
|
||||
render: function () {
|
||||
var entry = this.props.entry;
|
||||
var image = entry.getIn(['data', 'image']);
|
||||
var image = entry.data.image;
|
||||
var bg = this.props.getAsset(image);
|
||||
return h('div', {},
|
||||
h('h1', {}, entry.getIn(['data', 'title'])),
|
||||
h('img', {src: bg.toString()}),
|
||||
h('div', {"className": "text"}, this.props.widgetFor('body'))
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
h('h1', {}, entry.data.title),
|
||||
h('img', { src: bg.toString() }),
|
||||
h('div', { className: 'text' }, this.props.widgetFor('body')),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
CMS.registerPreviewTemplate("posts", PostPreview);
|
||||
CMS.registerPreviewTemplate('posts', PostPreview);
|
||||
</script>
|
||||
```
|
||||
* document: The preview pane iframe's [document instance](https://github.com/ryanseddon/react-frame-component/tree/9f8f06e1d3fc40da7122f0a57c62f7dec306e6cb#accessing-the-iframes-window-and-document).
|
||||
* window: The preview pane iframe's [window instance](https://github.com/ryanseddon/react-frame-component/tree/9f8f06e1d3fc40da7122f0a57c62f7dec306e6cb#accessing-the-iframes-window-and-document).
|
||||
|
||||
- document: The preview pane iframe's [document instance](https://github.com/ryanseddon/react-frame-component/tree/9f8f06e1d3fc40da7122f0a57c62f7dec306e6cb#accessing-the-iframes-window-and-document).
|
||||
- window: The preview pane iframe's [window instance](https://github.com/ryanseddon/react-frame-component/tree/9f8f06e1d3fc40da7122f0a57c62f7dec306e6cb#accessing-the-iframes-window-and-document).
|
||||
|
||||
### Lists and Objects
|
||||
The API for accessing the individual fields of list- and object-type entries is similar to the API for accessing fields in standard entries, but there are a few key differences. Access to these nested fields is facilitated through the `widgetsFor` function, which is passed to the preview template component during render.
|
||||
**Note**: as is often the case with the Static CMS API, arrays and objects are created with Immutable.js. If some of the methods that we use are unfamiliar, such as `getIn`, check out [their docs](https://facebook.github.io/immutable-js/docs/#/) to get a better understanding.
|
||||
**List Example:**
|
||||
```html
|
||||
<script>
|
||||
|
||||
The API for accessing the individual fields of list- and object-type entries is similar to the API for accessing fields in standard entries, but there are a few key differences. Access to these nested fields is facilitated through the `widgetsFor` function, which is passed to the preview template component during render.
|
||||
**Note**: as is often the case with the Static CMS API, arrays and objects are created with Immutable.js. If some of the methods that we use are unfamiliar, such as `getIn`, check out [their docs](https://facebook.github.io/immutable-js/docs/#/) to get a better understanding.
|
||||
**List Example:**
|
||||
|
||||
```html
|
||||
<script>
|
||||
var AuthorsPreview = createClass({
|
||||
// For list fields, the widgetFor function returns an array of objects
|
||||
// that you can map over in your template. If our field is a list of
|
||||
@ -113,31 +81,36 @@ Registers a template for a folder collection or an individual file in a file col
|
||||
//
|
||||
// Templating would look something like this:
|
||||
|
||||
render: function() {
|
||||
return h('div', {},
|
||||
render: function () {
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
|
||||
// This is a static header that would only be rendered once for the entire list
|
||||
h('h1', {}, 'Authors'),
|
||||
|
||||
// Here we provide a simple mapping function that will be applied to each
|
||||
// object in the array of authors
|
||||
this.props.widgetsFor('authors').map(function(author, index) {
|
||||
return h('div', {key: index},
|
||||
this.props.widgetsFor('authors').map(function (author, index) {
|
||||
return h(
|
||||
'div',
|
||||
{ key: index },
|
||||
h('hr', {}),
|
||||
h('strong', {}, author.getIn(['data', 'name'])),
|
||||
author.getIn(['widgets', 'description'])
|
||||
h('strong', {}, author.data.name),
|
||||
author.widgets.description,
|
||||
);
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
CMS.registerPreviewTemplate("authors", AuthorsPreview);
|
||||
</script>
|
||||
```
|
||||
|
||||
**Object Example:**
|
||||
```html
|
||||
<script>
|
||||
CMS.registerPreviewTemplate('authors', AuthorsPreview);
|
||||
</script>
|
||||
```
|
||||
|
||||
**Object Example:**
|
||||
|
||||
```html
|
||||
<script>
|
||||
var GeneralPreview = createClass({
|
||||
// Object fields are simpler than lists - instead of `widgetsFor` returning
|
||||
// an array of objects, it returns a single object. Accessing the shape of
|
||||
@ -147,38 +120,28 @@ Registers a template for a folder collection or an individual file in a file col
|
||||
// data: { front_limit: 0, author: 'Chris' },
|
||||
// widgets: { front_limit: (<WidgetComponent>), author: (WidgetComponent>)}
|
||||
// }
|
||||
render: function() {
|
||||
render: function () {
|
||||
var entry = this.props.entry;
|
||||
var title = entry.getIn(['data', 'site_title']);
|
||||
var posts = entry.getIn(['data', 'posts']);
|
||||
var title = entry.data.site_title;
|
||||
var posts = entry.data.posts;
|
||||
|
||||
return h('div', {},
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
h('h1', {}, title),
|
||||
h('dl', {},
|
||||
h(
|
||||
'dl',
|
||||
{},
|
||||
h('dt', {}, 'Posts on Frontpage'),
|
||||
h('dd', {}, this.props.widgetsFor('posts').getIn(['widgets', 'front_limit']) || 0),
|
||||
h('dd', {}, this.props.widgetsFor('posts').widgets.front_limit || 0),
|
||||
|
||||
h('dt', {}, 'Default Author'),
|
||||
h('dd', {}, this.props.widgetsFor('posts').getIn(['data', 'author']) || 'None'),
|
||||
)
|
||||
h('dd', {}, this.props.widgetsFor('posts').data.author || 'None'),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
CMS.registerPreviewTemplate("general", GeneralPreview);
|
||||
</script>
|
||||
```
|
||||
### Accessing Metadata
|
||||
Preview Components also receive an additional prop: `fieldsMetaData`. It contains aditional information (besides the plain textual value of each field) that can be useful for preview purposes. For example, the Relation widget passes the whole selected relation data in `fieldsMetaData`.
|
||||
```js
|
||||
export default class ArticlePreview extends React.Component {
|
||||
render() {
|
||||
const {entry, fieldsMetaData} = this.props;
|
||||
const author = fieldsMetaData.getIn(['authors', data.author]);
|
||||
|
||||
return <article><h2>{ entry.getIn(['data', 'title']) }</h2>
|
||||
{author &&<AuthorBio author={author.toJS()}/>}
|
||||
</article>
|
||||
}
|
||||
}
|
||||
```
|
||||
CMS.registerPreviewTemplate('general', GeneralPreview);
|
||||
</script>
|
||||
```
|
||||
|
@ -296,4 +296,4 @@ Finally, add the following to the collections array in `config.yml`
|
||||
- { label: Link, name: link, widget: string }
|
||||
```
|
||||
|
||||
Now you can add, rename, and rearrange the navigation items on your blog.
|
||||
Now you can add, rename, and rearrange the navigation items on your blog.
|
||||
|
@ -10,13 +10,13 @@ The color widget translates a color picker to a color string.
|
||||
- **Data type:** string
|
||||
- **Options:**
|
||||
- `default`: accepts a string; defaults to an empty string. Sets the default value
|
||||
- `allowInput`: accepts a boolean, defaults to `false`. Allows manual editing of the color input value
|
||||
- `enableAlpha`: accepts a boolean, defaults to `false`. Enables Alpha editing
|
||||
- `allow_input`: accepts a boolean, defaults to `false`. Allows manual editing of the color input value
|
||||
- `enable_alpha`: accepts a boolean, defaults to `false`. Enables Alpha editing
|
||||
- **Example:**
|
||||
```yaml
|
||||
- { label: 'Color', name: 'color', widget: 'color' }
|
||||
```
|
||||
- **Example:**
|
||||
```yaml
|
||||
- { label: 'Color', name: 'color', widget: 'color', enableAlpha: true, allowInput: true }
|
||||
- { label: 'Color', name: 'color', widget: 'color', enable_alpha: true, allow_input: true }
|
||||
```
|
||||
|
@ -15,7 +15,6 @@ The markdown widget provides a full fledged text editor allowing users to format
|
||||
* `minimal`: accepts a boolean value, `false` by default. Sets the widget height to minimum possible.
|
||||
* `buttons`: an array of strings representing the formatting buttons to display (all shown by default). Buttons include: `bold`, `italic`, `code`, `link`, `heading-one`, `heading-two`, `heading-three`, `heading-four`, `heading-five`, `heading-six`, `quote`, `bulleted-list`, and `numbered-list`.
|
||||
* `editor_components`: an array of strings representing the names of editor components to display (all shown by default). Static CMS includes `image` and `code-block` editor components by default, and custom components may be [created and registered](/docs/custom-widgets/#registereditorcomponent).
|
||||
* `modes`: an array of strings representing the names of allowed editor modes. Possible modes are `raw` and `rich_text`. A toggle button appears in the toolbar when more than one mode is available.
|
||||
* `sanitize_preview`: accepts a boolean value, `false` by default. Sanitizes markdown preview to prevent XSS attacks - might alter the preview content.
|
||||
* **Example:**
|
||||
|
||||
|
Reference in New Issue
Block a user