Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ This documentation will explain all the files and directories in the starter kit
│ │ └── sections/
│ ├── admin/
│ │ ├── config.yml
│ │ ├── decap-preview-styles.css
│ │ └── index.html
│ │ ├── index.html
│ │ └── previews.jsx
│ ├── assets/
│ │ ├── favicons/
│ │ ├── fonts/
Expand Down Expand Up @@ -301,15 +301,17 @@ Styling the Decap preview pane This template includes custom styles for the Deca

1. How it works:

The preview styles are defined in /admin/decap-preview-styles.css. The CMS preview script in /admin/index.html:
The preview styles are pulled from the same styles that are defined in your production styles, so make sure that you keep the JSX in sync for a true "live editing" experience. The CMS preview script can be found in in /admin/previews.jsx:

- pulls the props from the collection
- creates the DOM elements
- registers these elements and styles for the preview panel to use

The templates are written in JSX and compiled in the browser by @babel/standalone, which /admin/index.html loads before it loads previews.jsx. Keep them in their own .jsx file rather than inlining them in index.html to prevent formatters as treating them as HTML.

2. How to update or customize:

Edit /admin/decap-preview-styles.css and the preview pane script in /admin/index.html to match your site's branding or layout changes. Use Decap's documentation on [customizing the preview pane](https://decapcms.org/docs/customization/)
Edit /admin/previews.jsx to match your site's branding or layout changes. Use Decap's documentation on [customizing the preview pane](https://decapcms.org/docs/customization/)

3.Notes

Expand Down
7 changes: 6 additions & 1 deletion src/admin/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ collections:
}
- { label: "Description", name: "description", widget: "string" }
- { label: "Author", name: "author", widget: "string" }
- { label: "Date", name: "date", widget: "datetime" }
- {
label: "Date",
name: "date",
widget: "datetime",
default: "{{now}}",
}
- { label: "Tags", name: "tags", widget: "list", default: ["post"] }
- { label: "Featured Image", name: "image", widget: "image" }
- { label: "Image Caption", name: "imageAlt", widget: "string" }
Expand Down
127 changes: 0 additions & 127 deletions src/admin/decap-preview-styles.css

This file was deleted.

72 changes: 12 additions & 60 deletions src/admin/index.html
Original file line number Diff line number Diff line change
@@ -1,68 +1,20 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>

<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<title>Content Manager</title>
</head>

<title>Content Manager</title>
</head>
<body>
<!-- First - Render Decap script to expose tools to build previews -->
<script src="https://unpkg.com/decap-cms@3.15.1/dist/decap-cms.js"></script>

<body>
<script src="https://unpkg.com/decap-cms@3.0.0/dist/decap-cms.js"></script>

<!-- Decap CMS preview pane script -->
<!-- Edit this script to customize the preview pane for your blog posts. -->
<!-- Documentation: https://decapcms.org/docs/customization/ -->
<script type="text/babel">
const BlogPreview = createClass({
render: function () {
// Get all the props from the collection
const data = this.props.entry.get("data").toJS();
const { title, author, date: rawDate, image } = data;
const date = typeof rawDate === "string" ? new Date(rawDate) : rawDate;
let formattedDate = "";
if (date) {
formattedDate = Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
year: "numeric"
}).format(date);
}

const cover = this.props.getAsset(image);

// Create elements for the preview pane in JSX, to be processed by Babel
return (
<div className="blog">
<h1 className="title">{title}</h1>

<div className="metadata">
<span className="author">{author}</span>
<span className="dot"></span>
<span className="date">{formattedDate}</span>
</div>

<img src={cover?.toString()} className="cover" alt="Cover" />

<hr className="divider" />

<div className="markdown">
{this.props.widgetFor("body")}
</div>
</div>
);
}
});

// Register the elements and styles for the "blog" collection
CMS.registerPreviewTemplate("blog", BlogPreview);
CMS.registerPreviewStyle("/admin/decap-preview-styles.css");
</script>
</body>
<!-- Second - Use Decap's API to render custom previews for collections in React syntax enabled by Babel -->
<script type="text/babel" src="/admin/previews.jsx"></script>
</body>

</html>
83 changes: 83 additions & 0 deletions src/admin/previews.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/** @jsx h */
/* ^ Compile JSX with Decap's own renderer instead of React.createElement */

/*
Preview Pane Templates
============================================

Edit this file to customize the preview pane for your collections.
Documentation: https://decapcms.org/docs/customization/

At the bottom of the file, we load the same stylesheets used on the site.
Therefore, please keep the HTML in the preview in-sync with what's used on
the site to ensure the previews work correctly.
*/

const { createClass, h } = window;

/* Resolve an image path to a URL. Unsaved uploads only exist as blobs. */
function assetUrl(getAsset, path) {
if (!path || typeof path !== "string") return "";
try {
const asset = getAsset(path);
return asset ? asset.toString() : "";
} catch (error) {
return path;
}
}

/* Mirror of the site's postDate filter (src/config/filters/postDate.js) */
function postDate(value) {
if (!value) return "";
const date = value instanceof Date ? value : new Date(value);
if (isNaN(date.getTime())) return "";
return new Intl.DateTimeFormat(undefined, {
year: "numeric",
month: "short",
day: "numeric"
}).format(date);
}

/* Mirrors the blog layout's markup so the preview reuses the site's CSS */
const BlogPreview = createClass({
render: function () {
/* Live form values, re-rendered on every keystroke */
const data = this.props.entry.get("data").toJS();
const cover = assetUrl(this.props.getAsset, data.image);

return (
<main id="main">
<div id="single-article">
<div className="cs-container">
<article className="cs-article-post">
<picture className="cs-article-image">
<img src={cover} alt={data.imageAlt || ""} width="800" height="400" loading="lazy" decoding="async" aria-hidden="true" />
</picture>
<div className="cs-article-group">
<h1 className="cs-article-title">{data.title}</h1>
<div className="cs-author-group">
<picture className="cs-author-img">
<img src="/assets/svgs/profile.svg" alt="Profile icon" width="32" height="32" decoding="async" loading="lazy" aria-hidden="true" />
</picture>
<span className="cs-author-name">{data.author}</span>
<span aria-hidden="true" className="cs-dot"></span>
<span className="cs-date">{postDate(data.date)}</span>
</div>
</div>
<section className="cs-article-content">
{this.props.widgetFor("body")}
</section>
</article>
</div>
</div>
</main>
);
}
});

/* Bind the template to the "blog" collection in config.yml */
CMS.registerPreviewTemplate("blog", BlogPreview);

/* The preview renders in a bare iframe, so pull in the site's stylesheets */
CMS.registerPreviewStyle("/assets/css/root.css");
CMS.registerPreviewStyle("/assets/css/blog.css");