feat: bundle demo
This commit is contained in:
parent
f764dd6c24
commit
9627fb6814
@ -2,3 +2,4 @@ node_modules
|
|||||||
dist
|
dist
|
||||||
dev-test
|
dev-test
|
||||||
*.js
|
*.js
|
||||||
|
*.jsx
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"build": "lerna run build",
|
"build": "lerna run build",
|
||||||
"build:demo": "cd packages/demo && yarn build",
|
"build:demo": "cd packages/demo && yarn build",
|
||||||
"dev": "lerna run dev --scope=@staticcms/core",
|
"dev": "lerna run dev --scope=@staticcms/core",
|
||||||
|
"demo": "lerna run dev --scope=@staticcms/demo",
|
||||||
"docs": "lerna run dev --scope=docs",
|
"docs": "lerna run dev --scope=docs",
|
||||||
"format": "lerna run format",
|
"format": "lerna run format",
|
||||||
"lint": "lerna run lint",
|
"lint": "lerna run lint",
|
||||||
|
@ -122,12 +122,6 @@ module.exports = {
|
|||||||
{ functions: false, classes: true, variables: true },
|
{ functions: false, classes: true, variables: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
files: ['website/**/*'],
|
|
||||||
rules: {
|
|
||||||
'import/no-unresolved': [0],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Register all the things
|
// Register all the things
|
||||||
CMS.init();
|
CMS.init();
|
||||||
|
|
||||||
const PostPreview = ({ entry, widgetFor, widgetsFor }) => {
|
const PostPreview = ({ entry, widgetFor }) => {
|
||||||
return h(
|
return h(
|
||||||
'div',
|
'div',
|
||||||
{},
|
{},
|
||||||
|
56
packages/demo/.gitignore
vendored
Normal file
56
packages/demo/.gitignore
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
|
||||||
|
dist/
|
||||||
|
bin/
|
||||||
|
.tern-project
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
manifest.yml
|
||||||
|
.imdone/
|
||||||
|
data/contributors.json
|
||||||
|
cypress/videos
|
||||||
|
cypress/screenshots
|
||||||
|
__diff_output__
|
||||||
|
.cache
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
.temp/
|
||||||
|
*.tgz
|
||||||
|
public/sw.js
|
||||||
|
public/workbox*.js
|
||||||
|
|
2
packages/demo/dist/index.html
vendored
2
packages/demo/dist/index.html
vendored
@ -245,7 +245,7 @@ widget: 'markdown',
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="https://unpkg.com/@staticcms/app@1.0.0-beta.12/dist/static-cms-app.js"></script>
|
|
||||||
<script type="module" src="./index.js"></script>
|
<script type="module" src="./index.js"></script>
|
||||||
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
474
packages/demo/dist/index.js
vendored
474
packages/demo/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@ -3,14 +3,45 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack",
|
"dev": "react-scripts start",
|
||||||
"dev": "webpack serve"
|
"build": "react-scripts build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@staticcms/app": "^1.0.0-beta.12"
|
"@babel/eslint-parser": "7.19.1",
|
||||||
|
"@staticcms/core": "^1.0.0-beta.12",
|
||||||
|
"babel-loader": "9.1.2",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/cli": "7.20.7",
|
||||||
|
"@babel/core": "7.20.12",
|
||||||
|
"@babel/plugin-syntax-flow": "7.18.6",
|
||||||
|
"@babel/plugin-transform-react-jsx": "7.20.7",
|
||||||
"copy-webpack-plugin": "11.0.0",
|
"copy-webpack-plugin": "11.0.0",
|
||||||
|
"eslint-import-resolver-typescript": "3.5.3",
|
||||||
|
"eslint-plugin-cypress": "2.12.1",
|
||||||
|
"eslint-plugin-import": "2.27.4",
|
||||||
|
"eslint-plugin-prettier": "4.2.1",
|
||||||
|
"eslint-plugin-react-hooks": "4.6.0",
|
||||||
|
"eslint-plugin-react": "7.32.0",
|
||||||
|
"eslint-plugin-unicorn": "45.0.2",
|
||||||
|
"eslint": "8.31.0",
|
||||||
|
"prettier": "2.8.2",
|
||||||
|
"react-scripts": "5.0.1",
|
||||||
|
"typescript": "4.9.4",
|
||||||
"webpack": "5.75.0"
|
"webpack": "5.75.0"
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
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
|
import React from 'react';
|
||||||
CMS.init();
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
const PostPreview = ({ entry, widgetFor, widgetsFor }) => {
|
import './cms';
|
||||||
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')),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const GeneralPreview = ({ widgetsFor, getAsset, entry }) => {
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
const title = entry.data.site_title;
|
root.render(
|
||||||
const posts = entry.data.posts;
|
<React.StrictMode>
|
||||||
const thumb = posts && posts.thumb;
|
<div />
|
||||||
|
</React.StrictMode>,
|
||||||
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}`,
|
|
||||||
},
|
|
||||||
'',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
const path = require("path");
|
|
||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
||||||
|
|
||||||
const devServerPort = parseInt(process.env.STATIC_CMS_DEMO_DEV_SERVER_PORT || `${3300}`);
|
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: "./src/index.js",
|
|
||||||
mode: isProduction ? "production" : "development",
|
|
||||||
plugins: [
|
|
||||||
new CopyWebpackPlugin({
|
|
||||||
patterns: [{ from: "public" }],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist"),
|
|
||||||
filename: "index.js",
|
|
||||||
},
|
|
||||||
devServer: {
|
|
||||||
static: {
|
|
||||||
directory: "./dev-test",
|
|
||||||
},
|
|
||||||
host: "0.0.0.0",
|
|
||||||
port: devServerPort,
|
|
||||||
hot: true,
|
|
||||||
},
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user