feat: bundle demo
This commit is contained in:
156
packages/demo/src/cms.jsx
Normal file
156
packages/demo/src/cms.jsx
Normal file
@ -0,0 +1,156 @@
|
||||
import cms, { useMediaAsset } from "@staticcms/core";
|
||||
|
||||
// Register all the things
|
||||
cms.init();
|
||||
|
||||
const PostPreview = ({ entry, widgetFor }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="cover">
|
||||
<h1>{entry.data.title}</h1>
|
||||
{widgetFor("image")}
|
||||
</div>
|
||||
<p>
|
||||
<small>Written {entry.data.date}</small>
|
||||
</p>
|
||||
<div className="text">{widgetFor("body")}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const GeneralPreview = ({ widgetsFor, entry }) => {
|
||||
const title = entry.data.site_title;
|
||||
const posts = entry.data.posts;
|
||||
const thumb = posts && posts.thumb;
|
||||
|
||||
const thumbUrl = useMediaAsset(thumb);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
<dl>
|
||||
<dt>Posts on Frontpage</dt>
|
||||
<dd>{widgetsFor("posts").widgets.front_limit ?? 0}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Default Author</dt>
|
||||
<dd>{widgetsFor("posts").data?.author ?? "None"}</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Default Thumbnail</dt>
|
||||
<dd>{thumb && <img src={thumbUrl} />}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AuthorsPreview = ({ widgetsFor }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Authors</h1>
|
||||
{widgetsFor("authors").map((author, index) => (
|
||||
<div key={index}>
|
||||
<hr />
|
||||
<strong>{author.data.name}</strong>
|
||||
{author.widgets.description}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const RelationKitchenSinkPostPreview = ({ fieldsMetaData }) => {
|
||||
// When a post is selected from the relation field, all of it's data
|
||||
// will be available in the field's metadata nested under the collection
|
||||
// name, and then further nested under the value specified in `value_field`.
|
||||
// In this case, the post would be nested under "posts" and then under
|
||||
// the title of the selected post, since our `value_field` in the config
|
||||
// is "title".
|
||||
const post = fieldsMetaData && fieldsMetaData.posts.value;
|
||||
|
||||
if (!post) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ border: "2px solid #ccc", borderRadius: "8px", padding: "20px" }}>
|
||||
<h2>Related Post</h2>
|
||||
<h3>{post.title}</h3>
|
||||
<img src={post.image} />
|
||||
<p>{(post.body ?? "").slice(0, 100) + "..."}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomPage = () => {
|
||||
return <div>I am a custom page!</div>;
|
||||
};
|
||||
|
||||
cms.registerPreviewStyle(".toastui-editor-contents h1 { color: blue }", { raw: true });
|
||||
cms.registerPreviewTemplate("posts", PostPreview);
|
||||
cms.registerPreviewTemplate("general", GeneralPreview);
|
||||
cms.registerPreviewTemplate("authors", AuthorsPreview);
|
||||
// Pass the name of a registered control to reuse with a new widget preview.
|
||||
cms.registerWidget("relationKitchenSinkPost", "relation", RelationKitchenSinkPostPreview);
|
||||
cms.registerAdditionalLink({
|
||||
id: "docs",
|
||||
title: "Static CMS Docs",
|
||||
data: "https://staticjsCMS.netlify.app/",
|
||||
options: {
|
||||
icon: "page",
|
||||
},
|
||||
});
|
||||
cms.registerAdditionalLink({
|
||||
id: "config",
|
||||
title: "Demo config.yml",
|
||||
data: "https://github.com/StaticJsCMS/static-cms/blob/main/packages/demo/config.yml",
|
||||
options: {
|
||||
icon: "page",
|
||||
},
|
||||
});
|
||||
cms.registerAdditionalLink({
|
||||
id: "custom-page",
|
||||
title: "Custom Page",
|
||||
data: CustomPage,
|
||||
options: {
|
||||
icon: "page",
|
||||
},
|
||||
});
|
||||
|
||||
cms.registerShortcode("youtube", {
|
||||
label: "YouTube",
|
||||
openTag: "[",
|
||||
closeTag: "]",
|
||||
separator: "|",
|
||||
toProps: (args) => {
|
||||
if (args.length > 0) {
|
||||
return { src: args[0] };
|
||||
}
|
||||
|
||||
return { src: "" };
|
||||
},
|
||||
toArgs: ({ src }) => {
|
||||
return [src];
|
||||
},
|
||||
control: ({ src, onChange }) => {
|
||||
return (
|
||||
<span>
|
||||
<input
|
||||
key="control-input"
|
||||
value={src}
|
||||
onChange={(event) => {
|
||||
onChange({ src: event.target.value });
|
||||
}}
|
||||
/>
|
||||
<iframe key="control-preview" width="420" height="315" src={`https://www.youtube.com/embed/${src}`} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
preview: ({ src }) => {
|
||||
return (
|
||||
<span>
|
||||
<iframe width="420" height="315" src={`https://www.youtube.com/embed/${src}`} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
});
|
@ -1,181 +1,11 @@
|
||||
// Register all the things
|
||||
CMS.init();
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
const PostPreview = ({ entry, widgetFor, widgetsFor }) => {
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
h('div', { className: 'cover' }, h('h1', {}, entry.data.title), widgetFor('image')),
|
||||
h('p', {}, h('small', {}, 'Written ' + entry.data.date)),
|
||||
h('div', { className: 'text' }, widgetFor('body')),
|
||||
);
|
||||
};
|
||||
import './cms';
|
||||
|
||||
const GeneralPreview = ({ widgetsFor, getAsset, entry }) => {
|
||||
const title = entry.data.site_title;
|
||||
const posts = entry.data.posts;
|
||||
const thumb = posts && posts.thumb;
|
||||
|
||||
const [thumbUrl, setThumbUrl] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
|
||||
const loadThumb = async () => {
|
||||
const thumbAsset = await getAsset(thumb);
|
||||
if (alive) {
|
||||
setThumbUrl(thumbAsset.toString());
|
||||
}
|
||||
};
|
||||
|
||||
loadThumb();
|
||||
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, [thumb]);
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
h('h1', {}, title),
|
||||
h(
|
||||
'dl',
|
||||
{},
|
||||
h('dt', {}, 'Posts on Frontpage'),
|
||||
h('dd', {}, widgetsFor('posts').widgets.front_limit ?? 0),
|
||||
|
||||
h('dt', {}, 'Default Author'),
|
||||
h('dd', {}, widgetsFor('posts').data?.author ?? 'None'),
|
||||
|
||||
h('dt', {}, 'Default Thumbnail'),
|
||||
h('dd', {}, thumb && h('img', { src: thumbUrl })),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const AuthorsPreview = ({ widgetsFor }) => {
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
h('h1', {}, 'Authors'),
|
||||
widgetsFor('authors').map(function (author, index) {
|
||||
return h(
|
||||
'div',
|
||||
{ key: index },
|
||||
h('hr', {}),
|
||||
h('strong', {}, author.data.name),
|
||||
author.widgets.description,
|
||||
);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const RelationKitchenSinkPostPreview = ({ fieldsMetaData }) => {
|
||||
// When a post is selected from the relation field, all of it's data
|
||||
// will be available in the field's metadata nested under the collection
|
||||
// name, and then further nested under the value specified in `value_field`.
|
||||
// In this case, the post would be nested under "posts" and then under
|
||||
// the title of the selected post, since our `value_field` in the config
|
||||
// is "title".
|
||||
const post = fieldsMetaData && fieldsMetaData.posts.value;
|
||||
const style = { border: '2px solid #ccc', borderRadius: '8px', padding: '20px' };
|
||||
return post
|
||||
? h(
|
||||
'div',
|
||||
{ style: style },
|
||||
h('h2', {}, 'Related Post'),
|
||||
h('h3', {}, post.title),
|
||||
h('img', { src: post.image }),
|
||||
h('p', {}, (post.body ?? '').slice(0, 100) + '...'),
|
||||
)
|
||||
: null;
|
||||
};
|
||||
|
||||
const CustomPage = () => {
|
||||
return h('div', {}, 'I am a custom page!');
|
||||
};
|
||||
|
||||
CMS.registerPreviewStyle('.toastui-editor-contents h1 { color: blue }', { raw: true });
|
||||
CMS.registerPreviewTemplate('posts', PostPreview);
|
||||
CMS.registerPreviewTemplate('general', GeneralPreview);
|
||||
CMS.registerPreviewTemplate('authors', AuthorsPreview);
|
||||
// Pass the name of a registered control to reuse with a new widget preview.
|
||||
CMS.registerWidget('relationKitchenSinkPost', 'relation', RelationKitchenSinkPostPreview);
|
||||
CMS.registerAdditionalLink({
|
||||
id: 'docs',
|
||||
title: 'Static CMS Docs',
|
||||
data: 'https://staticjscms.netlify.app/',
|
||||
options: {
|
||||
icon: 'page',
|
||||
},
|
||||
});
|
||||
CMS.registerAdditionalLink({
|
||||
id: 'config',
|
||||
title: 'Demo config.yml',
|
||||
data: 'https://github.com/StaticJsCMS/static-cms/blob/main/packages/demo/config.yml',
|
||||
options: {
|
||||
icon: 'page',
|
||||
},
|
||||
});
|
||||
CMS.registerAdditionalLink({
|
||||
id: 'custom-page',
|
||||
title: 'Custom Page',
|
||||
data: CustomPage,
|
||||
options: {
|
||||
icon: 'page',
|
||||
},
|
||||
});
|
||||
|
||||
CMS.registerShortcode('youtube', {
|
||||
label: 'YouTube',
|
||||
openTag: '[',
|
||||
closeTag: ']',
|
||||
separator: '|',
|
||||
toProps: args => {
|
||||
if (args.length > 0) {
|
||||
return { src: args[0] };
|
||||
}
|
||||
|
||||
return { src: '' };
|
||||
},
|
||||
toArgs: ({ src }) => {
|
||||
return [src];
|
||||
},
|
||||
control: ({ src, onChange }) => {
|
||||
return h('span', {}, [
|
||||
h('input', {
|
||||
key: 'control-input',
|
||||
value: src,
|
||||
onChange: event => {
|
||||
onChange({ src: event.target.value });
|
||||
},
|
||||
}),
|
||||
h(
|
||||
'iframe',
|
||||
{
|
||||
key: 'control-preview',
|
||||
width: '420',
|
||||
height: '315',
|
||||
src: `https://www.youtube.com/embed/${src}`,
|
||||
},
|
||||
'',
|
||||
),
|
||||
]);
|
||||
},
|
||||
preview: ({ src }) => {
|
||||
return h(
|
||||
'span',
|
||||
{},
|
||||
h(
|
||||
'iframe',
|
||||
{
|
||||
width: '420',
|
||||
height: '315',
|
||||
src: `https://www.youtube.com/embed/${src}`,
|
||||
},
|
||||
'',
|
||||
),
|
||||
);
|
||||
},
|
||||
});
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<div />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
Reference in New Issue
Block a user