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:
Shawn Erquhart 2018-10-01 20:00:57 -04:00 committed by GitHub
parent c261163eab
commit 6e453b3f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 143 additions and 162 deletions

46
website/.babelrc Normal file
View 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,
},
],
],
}

View File

@ -1,6 +1,6 @@
---
title: boolean
label: "Boolean"
target: boolean
---
The boolean widget translates a toggle switch input to a true/false value.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -53,7 +53,12 @@ module.exports = {
// prettier-ignore
plugins: [
'gatsby-remark-autolink-headers',
'gatsby-remark-prismjs'
{
resolve: 'gatsby-remark-prismjs',
options: {
noInlineHighlight: true,
},
},
]
},
},

View File

@ -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"
},

View File

@ -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);

View 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;

View File

@ -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>

View File

@ -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;
}

View File

@ -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
}

View File

@ -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"

View File

@ -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"