docs: make widget docs editable (#1782)
* make widget docs editable * update widget doc frontmatter keys * improve docs preview * fix formatting * fix preview * add prism highlighting for previews * fix formatting * restore cms branch
This commit is contained in:
parent
c261163eab
commit
6e453b3f08
46
website/.babelrc
Normal file
46
website/.babelrc
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
loose: true,
|
||||
modules: false,
|
||||
useBuiltIns: "usage",
|
||||
shippedProposals: true,
|
||||
targets: {
|
||||
browsers: [">0.25%", "not dead"],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"@babel/preset-react",
|
||||
{
|
||||
useBuiltIns: true,
|
||||
pragma: "React.createElement",
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
["prismjs", {
|
||||
"languages": ["javascript", "css", "markup", "yaml", "json"],
|
||||
"plugins": ["line-numbers"],
|
||||
"theme": "tomorrow",
|
||||
"css": true,
|
||||
}],
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
],
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"babel-plugin-macros",
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
helpers: true,
|
||||
regenerator: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: boolean
|
||||
label: "Boolean"
|
||||
target: boolean
|
||||
---
|
||||
|
||||
The boolean widget translates a toggle switch input to a true/false value.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: date
|
||||
label: "Date"
|
||||
target: date
|
||||
---
|
||||
|
||||
The date widget translates a date picker input to a date string. For saving date and time together, use the datetime widget.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: datetime
|
||||
label: "DateTime"
|
||||
target: datetime
|
||||
---
|
||||
|
||||
The datetime widget translates a datetime picker to a datetime string. For saving the date only, use the date widget.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "File"
|
||||
target: file
|
||||
title: file
|
||||
---
|
||||
|
||||
The file widget allows editors to upload a file or select an existing one from the media library. The path to the file will be saved to the field as a string.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Hidden"
|
||||
target: hidden
|
||||
title: hidden
|
||||
---
|
||||
|
||||
Hidden widgets do not display in the UI. In folder collections that allow users to create new items, you will often want to set a default for hidden fields, so they will be set without requiring an input.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Image"
|
||||
target: image
|
||||
title: image
|
||||
---
|
||||
|
||||
The image widget allows editors to upload an image or select an existing one from the media library. The path to the image file will be saved to the field as a string.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "List"
|
||||
target: list
|
||||
title: list
|
||||
---
|
||||
|
||||
The list widget allows you to create a repeatable item in the UI which saves as a list of widget values. map a user-provided string with a comma delimiter into a list. You can choose any widget as a child of a list widget—even other lists.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Markdown"
|
||||
target: markdown
|
||||
title: markdown
|
||||
---
|
||||
|
||||
The markdown widget provides a full fledged text editor - which is based on [slate](https://github.com/ianstormtaylor/slate) - that allows users to format text with features such as headings and blockquotes. Users are also allowed to write in markdown by simply flipping a switch.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Number"
|
||||
target: number
|
||||
title: number
|
||||
---
|
||||
|
||||
The number widget uses an HTML number input, saving the value as a string, integer, or floating point number.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Object"
|
||||
target: object
|
||||
title: object
|
||||
---
|
||||
|
||||
The object widget allows you to group multiple widgets together, nested under a single field. You can choose any widget as a child of an object widget—even other objects.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Relation"
|
||||
target: relation
|
||||
title: relation
|
||||
---
|
||||
|
||||
The relation widget allows you to reference items from another collection. It provides a search input with a list of entries from the collection you're referencing, and the list automatically updates with matched entries based on what you've typed.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Select"
|
||||
target: select
|
||||
title: select
|
||||
---
|
||||
|
||||
The select widget allows you to pick a single string value from a dropdown menu.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "String"
|
||||
target: string
|
||||
title: string
|
||||
---
|
||||
|
||||
The string widget translates a basic text input to a string value. For larger textarea inputs, use the text widget.
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
label: "Text"
|
||||
target: text
|
||||
title: text
|
||||
---
|
||||
|
||||
The text widget takes a multiline text field and saves it as a string. For shorter text inputs, use the string widget.
|
||||
|
@ -53,7 +53,12 @@ module.exports = {
|
||||
// prettier-ignore
|
||||
plugins: [
|
||||
'gatsby-remark-autolink-headers',
|
||||
'gatsby-remark-prismjs'
|
||||
{
|
||||
resolve: 'gatsby-remark-prismjs',
|
||||
options: {
|
||||
noInlineHighlight: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
|
@ -45,6 +45,7 @@
|
||||
"smooth-scroll": "^14.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-prismjs": "^1.0.2",
|
||||
"eslint": "^3.1.1",
|
||||
"eslint-plugin-import": "^1.11.1"
|
||||
},
|
||||
|
@ -1,16 +1,45 @@
|
||||
import React from 'react';
|
||||
import CMS from 'netlify-cms';
|
||||
import dayjs from 'dayjs';
|
||||
import Prism from 'prismjs';
|
||||
import { BlogPostTemplate } from '../templates/blog-post';
|
||||
import { DocsTemplate } from '../templates/doc-page';
|
||||
import WidgetDoc from '../components/widget-doc';
|
||||
import Release from '../components/release';
|
||||
import WhatsNew from '../components/whats-new';
|
||||
import Notification from '../components/notification';
|
||||
import '../css/lib/prism.css';
|
||||
import '../css/imports/docs.css';
|
||||
import '../css/imports/whatsnew.css';
|
||||
import '../css/imports/header.css';
|
||||
|
||||
const withHighlight = WrappedComponent =>
|
||||
class Highlight extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.ref = React.createRef();
|
||||
}
|
||||
|
||||
highlight() {
|
||||
Prism.highlightAllUnder(this.ref.current);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.highlight();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.highlight();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="language-markup" ref={this.ref}>
|
||||
<WrappedComponent {...this.props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const BlogPostPreview = ({ entry, widgetFor }) => {
|
||||
const data = entry.get('data');
|
||||
return (
|
||||
@ -27,6 +56,10 @@ const DocsPreview = ({ entry, widgetFor }) => (
|
||||
<DocsTemplate title={entry.getIn(['data', 'title'])} body={widgetFor('body')} />
|
||||
);
|
||||
|
||||
const WidgetDocPreview = ({ entry, widgetFor }) => (
|
||||
<WidgetDoc visible={true} label={entry.get('label')} body={widgetFor('body')} />
|
||||
);
|
||||
|
||||
const ReleasePreview = ({ entry }) => (
|
||||
<WhatsNew>
|
||||
{entry.getIn(['data', 'updates']).map((release, idx) => (
|
||||
@ -50,7 +83,8 @@ const NotificationPreview = ({ entry }) =>
|
||||
</Notification>
|
||||
));
|
||||
|
||||
CMS.registerPreviewTemplate('blog', BlogPostPreview);
|
||||
CMS.registerPreviewTemplate('docs', DocsPreview);
|
||||
CMS.registerPreviewTemplate('blog', withHighlight(BlogPostPreview));
|
||||
CMS.registerPreviewTemplate('docs', withHighlight(DocsPreview));
|
||||
CMS.registerPreviewTemplate('widget_docs', withHighlight(WidgetDocPreview));
|
||||
CMS.registerPreviewTemplate('releases', ReleasePreview);
|
||||
CMS.registerPreviewTemplate('notifications', NotificationPreview);
|
||||
|
11
website/src/components/widget-doc.js
Normal file
11
website/src/components/widget-doc.js
Normal file
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const WidgetDoc = ({ visible, label, body, html }) => (
|
||||
<div className={classnames('widget', { widget_open: visible })}>
|
||||
<h3>{label}</h3>
|
||||
{body ? body : <div dangerouslySetInnerHTML={{ __html: html }} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default WidgetDoc;
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import WidgetDoc from './widget-doc';
|
||||
|
||||
import '../css/imports/widgets.css';
|
||||
|
||||
@ -13,7 +14,7 @@ class Widgets extends Component {
|
||||
|
||||
const hash = window.location.hash ? window.location.hash.replace('#', '') : '';
|
||||
|
||||
const widgetsContainHash = widgets.edges.some(w => w.node.frontmatter.target === hash);
|
||||
const widgetsContainHash = widgets.edges.some(w => w.node.frontmatter.title === hash);
|
||||
|
||||
if (widgetsContainHash) {
|
||||
return this.setState({
|
||||
@ -22,18 +23,18 @@ class Widgets extends Component {
|
||||
}
|
||||
|
||||
this.setState({
|
||||
currentWidget: widgets.edges[0].node.frontmatter.target,
|
||||
currentWidget: widgets.edges[0].node.frontmatter.title,
|
||||
});
|
||||
}
|
||||
|
||||
handleWidgetChange = (event, target) => {
|
||||
handleWidgetChange = (event, title) => {
|
||||
event.preventDefault();
|
||||
this.setState(
|
||||
{
|
||||
currentWidget: target,
|
||||
currentWidget: title,
|
||||
},
|
||||
() => {
|
||||
window.history.pushState(null, null, `#${target}`);
|
||||
window.history.pushState(null, null, `#${title}`);
|
||||
},
|
||||
);
|
||||
};
|
||||
@ -47,14 +48,14 @@ class Widgets extends Component {
|
||||
<section className="widgets">
|
||||
<div className="widgets__cloud">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, target } = node.frontmatter;
|
||||
const { label, title } = node.frontmatter;
|
||||
return (
|
||||
<button
|
||||
key={target}
|
||||
key={title}
|
||||
className={classnames('widgets__item', {
|
||||
widgets__item_active: currentWidget === target,
|
||||
widgets__item_active: currentWidget === title,
|
||||
})}
|
||||
onClick={event => this.handleWidgetChange(event, target)}
|
||||
onClick={event => this.handleWidgetChange(event, title)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
@ -63,18 +64,10 @@ class Widgets extends Component {
|
||||
</div>
|
||||
<div className="widgets__container">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, target } = node.frontmatter;
|
||||
return (
|
||||
<div
|
||||
key={label}
|
||||
className={classnames('widget', {
|
||||
widget_open: currentWidget === target,
|
||||
})}
|
||||
>
|
||||
<h3>{label}</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: node.html }} />
|
||||
</div>
|
||||
);
|
||||
const { frontmatter, html } = node;
|
||||
const { title, label } = frontmatter;
|
||||
const isVisible = currentWidget === title;
|
||||
return <WidgetDoc key={label} visible={isVisible} label={label} html={html} />;
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
@ -1,120 +0,0 @@
|
||||
/**
|
||||
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
|
||||
* Based on https://github.com/chriskempson/tomorrow-theme
|
||||
* @author Rose Pritchard
|
||||
*/
|
||||
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
color: #ccc;
|
||||
background: none;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*='language-'] {
|
||||
padding: 1em;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
background: #2d2d2d;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*='language-'] {
|
||||
padding: 0.1em;
|
||||
border-radius: 0.3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.block-comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.attr-name,
|
||||
.token.namespace,
|
||||
.token.deleted {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #6196cc;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.function {
|
||||
color: #f08d49;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.symbol {
|
||||
color: #f8c555;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.important,
|
||||
.token.atrule,
|
||||
.token.keyword,
|
||||
.token.builtin {
|
||||
color: #cc99cd;
|
||||
}
|
||||
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.attr-value,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: #7ec699;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url {
|
||||
color: #67cdcc;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { graphql } from 'gatsby';
|
||||
import 'prismjs/themes/prism-tomorrow.css';
|
||||
|
||||
import Layout from '../components/layout';
|
||||
import EditLink from '../components/edit-link';
|
||||
@ -8,7 +9,6 @@ import Widgets from '../components/widgets';
|
||||
import DocsNav from '../components/docs-nav';
|
||||
import MobileNav from '../components/mobile-nav';
|
||||
|
||||
import '../css/lib/prism.css';
|
||||
import '../css/imports/docs.css';
|
||||
|
||||
const toMenu = (menu, nav) =>
|
||||
@ -124,8 +124,8 @@ export const pageQuery = graphql`
|
||||
edges {
|
||||
node {
|
||||
frontmatter {
|
||||
title
|
||||
label
|
||||
target
|
||||
}
|
||||
html
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
backend:
|
||||
name: github
|
||||
repo: netlify/netlify-cms
|
||||
branch: master
|
||||
squash_merges: true
|
||||
|
||||
publish_mode: editorial_workflow
|
||||
@ -19,6 +18,14 @@ collections: # A list of collections the CMS should be able to edit
|
||||
- {label: "Group", name: "group", widget: "string"}
|
||||
- {label: "Weight", name: "weight", widget: "number"}
|
||||
- {label: "Body", name: "body", widget: "markdown"}
|
||||
- name: "widget_docs" # Used in routes, ie.: /admin/collections/:slug/edit
|
||||
label: "Widget Docs" # Used in the UI, ie.: "New Post"
|
||||
folder: "website/content/docs/widgets" # The path to the folder where the documents are stored
|
||||
create: true # Allow users to create new documents in this collection
|
||||
fields: # The fields each document in this collection have
|
||||
- {label: "Name", name: "title"}
|
||||
- {label: "Label", name: "label"}
|
||||
- {label: "Body", name: "body", widget: "markdown"}
|
||||
- name: "blog"
|
||||
label: "Blog"
|
||||
label_singular: "Post"
|
||||
|
@ -1520,6 +1520,10 @@ babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.4.0:
|
||||
dependencies:
|
||||
cosmiconfig "^5.0.5"
|
||||
|
||||
babel-plugin-prismjs@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-prismjs/-/babel-plugin-prismjs-1.0.2.tgz#837bf6b32168b3ba624c054fc755946deb1b63fa"
|
||||
|
||||
babel-plugin-remove-graphql-queries@^2.0.2-rc.2:
|
||||
version "2.0.2-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-remove-graphql-queries/-/babel-plugin-remove-graphql-queries-2.0.2-rc.2.tgz#85ae3b8d46ebaa27e128d15321d67acd409d95e2"
|
||||
|
Loading…
x
Reference in New Issue
Block a user