feat: bundle demo

This commit is contained in:
Daniel Lautzenheiser 2023-01-13 11:46:56 -05:00
parent f764dd6c24
commit 9627fb6814
13 changed files with 3495 additions and 381 deletions

View File

@ -2,3 +2,4 @@ node_modules
dist dist
dev-test dev-test
*.js *.js
*.jsx

View File

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

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@ -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
View 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>
);
},
});

View File

@ -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', const root = ReactDOM.createRoot(document.getElementById('root'));
{}, root.render(
h('div', { className: 'cover' }, h('h1', {}, entry.data.title), widgetFor('image')), <React.StrictMode>
h('p', {}, h('small', {}, 'Written ' + entry.data.date)), <div />
h('div', { className: 'text' }, widgetFor('body')), </React.StrictMode>,
); );
};
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}`,
},
'',
),
);
},
});

View File

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

2783
yarn.lock

File diff suppressed because it is too large Load Diff