feat: v4.0.0 (#1016)
Co-authored-by: Denys Konovalov <kontakt@denyskon.de> Co-authored-by: Mathieu COSYNS <64072917+Mathieu-COSYNS@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
682576ffc4
commit
799c7e6936
4
packages/demo/.prettierignore
Normal file
4
packages/demo/.prettierignore
Normal file
@ -0,0 +1,4 @@
|
||||
dist/
|
||||
bin/
|
||||
public/
|
||||
.cache/
|
6
packages/demo/.prettierrc
Normal file
6
packages/demo/.prettierrc
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -8,33 +8,33 @@
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/eslint-parser": "7.21.3",
|
||||
"@staticcms/core": "^3.0.0-beta.1",
|
||||
"babel-loader": "9.1.2",
|
||||
"@babel/eslint-parser": "7.22.15",
|
||||
"@staticcms/core": "^4.0.0-beta.0",
|
||||
"babel-loader": "9.1.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.21.0",
|
||||
"@babel/core": "7.21.4",
|
||||
"@babel/plugin-syntax-flow": "7.21.4",
|
||||
"@babel/plugin-transform-react-jsx": "7.21.0",
|
||||
"@babel/cli": "7.23.0",
|
||||
"@babel/core": "7.23.0",
|
||||
"@babel/plugin-syntax-flow": "7.22.5",
|
||||
"@babel/plugin-transform-react-jsx": "7.22.15",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"autoprefixer": "10.4.14",
|
||||
"eslint": "8.39.0",
|
||||
"eslint-import-resolver-typescript": "3.5.5",
|
||||
"eslint-plugin-cypress": "2.13.3",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"autoprefixer": "10.4.16",
|
||||
"eslint": "8.50.0",
|
||||
"eslint-import-resolver-typescript": "3.6.1",
|
||||
"eslint-plugin-cypress": "2.15.1",
|
||||
"eslint-plugin-import": "2.28.1",
|
||||
"eslint-plugin-prettier": "5.0.0",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-unicorn": "46.0.1",
|
||||
"postcss": "8.4.23",
|
||||
"postcss-scss": "4.0.6",
|
||||
"prettier": "2.8.8",
|
||||
"vite": "4.3.9",
|
||||
"vite-plugin-svgr": "3.2.0",
|
||||
"webpack": "5.80.0"
|
||||
"eslint-plugin-unicorn": "48.0.1",
|
||||
"postcss": "8.4.31",
|
||||
"postcss-scss": "4.0.9",
|
||||
"prettier": "3.0.3",
|
||||
"vite": "4.5.0",
|
||||
"vite-plugin-svgr": "4.1.0",
|
||||
"webpack": "5.88.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
1
packages/demo/public/editor-friendly-user-interface.svg
Normal file
1
packages/demo/public/editor-friendly-user-interface.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="318" height="198" viewBox="0 0 318 198" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>editor</title><defs><rect id="b" width="300" height="180" rx="6"/><filter x="-6%" y="-7.8%" width="112%" filterUnits="objectBoundingBox" id="a"><feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.147843071 0" in="shadowBlurOuter1" result="shadowMatrixOuter1"/><feOffset dy="3" in="SourceAlpha" result="shadowOffsetOuter2"/><feGaussianBlur stdDeviation="4.5" in="shadowOffsetOuter2" result="shadowBlurOuter2"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0974298007 0" in="shadowBlurOuter2" result="shadowMatrixOuter2"/><feMerge><feMergeNode in="shadowMatrixOuter1"/><feMergeNode in="shadowMatrixOuter2"/></feMerge></filter><linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c"><stop stop-color="#4779DD" offset="0%"/><stop stop-color="#3A69C7" offset="100%"/></linearGradient></defs><g transform="translate(9 6)" fill="none" fill-rule="evenodd"><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill="#FFF" xlink:href="#b"/><path d="M0 19h149v161H6c-3.3137 0-6-2.6863-6-6V19z" fill="#EFF0F4"/><path fill="#AEB1BD" d="M10 31h18v4H10z"/><path fill="#FFF" d="M10 39h129v12H10z"/><path fill="#D4D6DD" d="M16 43h44v4H16z"/><path fill="#AEB1BD" d="M10 59h10v4H10z"/><path fill="#FFF" d="M10 67h129v12H10z"/><path fill="#D4D6DD" d="M16 71h26v4H16z"/><path fill="#AEB1BD" d="M10 87h35v4H10z"/><path fill="#FFF9E5" d="M10 95h42v27.7686H10z"/><circle fill="#FFC500" cx="31" cy="110.4463" r="7.8099"/><path d="M10 110.1683c4.6101 2.4917 9.3585 3.7375 14.245 3.7375 7.33 0 10.2112-5.0507 15.7083-5.0507 3.6648 0 7.6803 1.5082 12.0467 4.5246v9.3889H10v-12.6003z" fill="#D4D6DD"/><path d="M10 115.257c4.6503-2.702 8.896-4.0531 12.7373-4.0531 5.7618 0 11.322 4.9766 15.525 4.9766 2.8018 0 7.3811-2.196 13.7377-6.588v13.1761H10v-7.5116z" fill="#9AA1AE"/><path fill="#AEB1BD" d="M10 131h10v4H10z"/><path fill="#FFF" d="M10 139h129v41H10z"/><path fill="#D4D6DD" d="M16 145h117v4H16zm0 6h117v4H16zm0 6h83v4H16zm0 10h117v4H16zm0 6h43v4H16z"/><path fill="#9AA1AE" d="M61 172h2v6h-2z"/><path fill="#AEB1BD" d="M179 31h91v8h-91z"/><path fill="#D4D6DD" d="M213 42h24v4h-24z"/><path fill="#FFF9E5" d="M164 56h121v80H164z"/><circle fill="#FFC500" cx="224.5" cy="100.5" r="22.5"/><path d="M164 99.6992c13.2815 7.1784 26.9613 10.7676 41.0393 10.7676 21.117 0 29.4178-14.5508 45.2548-14.5508 10.558 0 22.1266 4.345 34.7059 13.0352V136H164V99.6992z" fill="#D4D6DD"/><path d="M164 114.3594c13.3973-7.7845 25.6291-11.6768 36.6955-11.6768 16.5995 0 32.6183 14.3374 44.7266 14.3374 8.0722 0 21.2648-6.3266 39.5779-18.98V136H164v-21.6406z" fill="#9AA1AE"/><path fill="#D4D6DD" d="M164 145h121v4H164zm0 6h121v4H164zm0 6h85.8376v4H164zm0 10h121v4H164zm0 6h44.4701v4H164z"/><path fill="#9AA1AE" d="M210 172h2v6h-2z"/><path d="M6 0h288c3.3137 0 6 2.6863 6 6v13H0V6c0-3.3137 2.6863-6 6-6z" fill="url(#c)"/></g></svg>
|
After Width: | Height: | Size: 3.0 KiB |
1551
packages/demo/public/editorial/config.yml
Normal file
1551
packages/demo/public/editorial/config.yml
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.1 KiB |
@ -1,7 +1,7 @@
|
||||
backend:
|
||||
name: test-repo
|
||||
site_url: 'https://staticcms.org/'
|
||||
media_folder: assets/uploads
|
||||
site_url: 'https://example.com'
|
||||
media_folder: /assets/uploads
|
||||
media_library:
|
||||
folder_support: true
|
||||
locale: en
|
||||
@ -17,7 +17,7 @@ i18n:
|
||||
|
||||
# Optional, defaults to the first item in locales.
|
||||
# The locale to be used for fields validation and as a baseline for the entry.
|
||||
defaultLocale: en
|
||||
default_locale: en
|
||||
collections:
|
||||
- name: posts
|
||||
label: Posts
|
||||
@ -30,7 +30,6 @@ collections:
|
||||
summary_fields:
|
||||
- title
|
||||
- date
|
||||
- draft
|
||||
sortable_fields:
|
||||
fields:
|
||||
- title
|
||||
@ -39,29 +38,25 @@ collections:
|
||||
field: title
|
||||
create: true
|
||||
view_filters:
|
||||
- label: Posts With Index
|
||||
field: title
|
||||
pattern: 'This is post #'
|
||||
- label: Posts Without Index
|
||||
field: title
|
||||
pattern: front matter post
|
||||
- label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
filters:
|
||||
- name: posts-with-index
|
||||
label: Posts With Index
|
||||
field: title
|
||||
pattern: 'This is post #'
|
||||
- name: posts-without-index
|
||||
label: Posts Without Index
|
||||
field: title
|
||||
pattern: front matter post
|
||||
view_groups:
|
||||
- label: Year
|
||||
field: date
|
||||
pattern: '\d{4}'
|
||||
- label: Drafts
|
||||
field: draft
|
||||
groups:
|
||||
- name: by-year
|
||||
label: Year
|
||||
field: date
|
||||
pattern: '\d{4}'
|
||||
fields:
|
||||
- label: Title
|
||||
name: title
|
||||
widget: string
|
||||
- label: Draft
|
||||
name: draft
|
||||
widget: boolean
|
||||
default: false
|
||||
- label: Publish Date
|
||||
name: date
|
||||
widget: datetime
|
||||
@ -75,7 +70,7 @@ collections:
|
||||
- label: Body
|
||||
name: body
|
||||
widget: markdown
|
||||
hint: Main content goes here.
|
||||
hint: "*Main* __content__ __*goes*__ [here](https://example.com/)."
|
||||
- name: faq
|
||||
label: FAQ
|
||||
folder: _faqs
|
||||
@ -149,6 +144,19 @@ collections:
|
||||
widget: boolean
|
||||
pattern: ['true', 'Must be true']
|
||||
required: false
|
||||
- name: prefix
|
||||
label: With Prefix
|
||||
widget: boolean
|
||||
prefix: "I'm a prefix"
|
||||
- name: suffix
|
||||
label: With Suffix
|
||||
widget: boolean
|
||||
suffix: "I'm a suffix"
|
||||
- name: prefix_and_suffix
|
||||
label: With Prefix and Suffix
|
||||
widget: boolean
|
||||
prefix: "I'm a prefix"
|
||||
suffix: "I'm a suffix"
|
||||
- name: code
|
||||
label: Code
|
||||
file: _widgets/code.json
|
||||
@ -570,6 +578,7 @@ collections:
|
||||
- label: Type 2 Object
|
||||
name: type_2_object
|
||||
widget: object
|
||||
summary: "{{datetime | date('yyyy-MM-dd')}}"
|
||||
fields:
|
||||
- label: Number
|
||||
name: number
|
||||
@ -777,6 +786,19 @@ collections:
|
||||
widget: number
|
||||
pattern: ['[0-9]{3,}', 'Must be at least 3 digits']
|
||||
required: false
|
||||
- name: prefix
|
||||
label: With Prefix
|
||||
widget: number
|
||||
prefix: '$'
|
||||
- name: suffix
|
||||
label: With Suffix
|
||||
widget: number
|
||||
suffix: '%'
|
||||
- name: prefix_and_suffix
|
||||
label: With Prefix and Suffix
|
||||
widget: number
|
||||
prefix: '$'
|
||||
suffix: '%'
|
||||
- name: object
|
||||
label: Object
|
||||
file: _widgets/object.json
|
||||
@ -1054,6 +1076,19 @@ collections:
|
||||
widget: string
|
||||
pattern: ['.{12,}', 'Must have at least 12 characters']
|
||||
required: false
|
||||
- name: prefix
|
||||
label: With Prefix
|
||||
widget: string
|
||||
prefix: '$'
|
||||
- name: suffix
|
||||
label: With Suffix
|
||||
widget: string
|
||||
suffix: '%'
|
||||
- name: prefix_and_suffix
|
||||
label: With Prefix and Suffix
|
||||
widget: string
|
||||
prefix: '$'
|
||||
suffix: '%'
|
||||
- name: text
|
||||
label: Text
|
||||
file: _widgets/text.json
|
||||
@ -1098,11 +1133,6 @@ collections:
|
||||
file: _data/settings.json
|
||||
description: General Site Settings
|
||||
fields:
|
||||
- label: Number of posts on frontpage
|
||||
name: front_limit
|
||||
widget: number
|
||||
min: 1
|
||||
max: 10
|
||||
- label: Global title
|
||||
name: site_title
|
||||
widget: string
|
170
packages/demo/src/cms.js
Normal file
170
packages/demo/src/cms.js
Normal file
@ -0,0 +1,170 @@
|
||||
import cms, { useMediaAsset } from '@staticcms/core';
|
||||
|
||||
import '@staticcms/core/dist/main.css';
|
||||
|
||||
import './data';
|
||||
|
||||
// Register all the things
|
||||
cms.init();
|
||||
|
||||
const PostPreview = ({ entry, widgetFor }) => {
|
||||
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 PostDateFieldPreview = ({ value }) => {
|
||||
const date = new Date(value);
|
||||
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{},
|
||||
`${date.getFullYear()}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`,
|
||||
);
|
||||
};
|
||||
|
||||
const GeneralPreview = ({ widgetsFor, entry, collection }) => {
|
||||
const title = entry.data.site_title;
|
||||
const posts = entry.data.posts;
|
||||
const thumb = posts && posts.thumb;
|
||||
|
||||
const thumbUrl = useMediaAsset(thumb, collection, undefined, entry);
|
||||
|
||||
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 CustomPage = () => {
|
||||
return h('div', {}, 'I am a custom page!');
|
||||
};
|
||||
|
||||
cms.registerPreviewTemplate('posts', PostPreview);
|
||||
cms.registerFieldPreview('posts', 'date', PostDateFieldPreview);
|
||||
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');
|
||||
cms.registerAdditionalLink({
|
||||
id: 'example',
|
||||
title: 'Example.com',
|
||||
data: 'https://example.com',
|
||||
options: {
|
||||
icon: 'page',
|
||||
},
|
||||
});
|
||||
cms.registerAdditionalLink({
|
||||
id: 'custom-page',
|
||||
title: 'Custom Page',
|
||||
data: CustomPage,
|
||||
options: {
|
||||
icon: 'page',
|
||||
},
|
||||
});
|
||||
|
||||
cms.registerTheme({
|
||||
name: 'Custom Red Orange',
|
||||
extends: 'dark',
|
||||
primary: {
|
||||
main: '#ff4500',
|
||||
},
|
||||
});
|
||||
|
||||
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 }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return h('span', {}, [
|
||||
h('input', {
|
||||
key: 'control-input',
|
||||
value: src,
|
||||
onChange: event => {
|
||||
onChange({ src: event.target.value });
|
||||
},
|
||||
style: {
|
||||
width: '100%',
|
||||
backgroundColor: theme.common.gray,
|
||||
color: theme.text.primary,
|
||||
padding: '4px 8px',
|
||||
},
|
||||
}),
|
||||
h(
|
||||
'iframe',
|
||||
{
|
||||
key: 'control-preview',
|
||||
width: '100%',
|
||||
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,300 +0,0 @@
|
||||
import cms, { useMediaAsset } from "@staticcms/core";
|
||||
|
||||
import "@staticcms/core/dist/main.css";
|
||||
|
||||
// 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 PostPreviewCard = ({ entry, theme, hasLocalBackup }) => {
|
||||
const date = new Date(entry.data.date);
|
||||
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
const image = entry.data.image;
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%" }}>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
borderTopLeftRadius: "8px",
|
||||
borderTopRightRadius: "8px",
|
||||
overflow: "hidden",
|
||||
height: "140px",
|
||||
backgroundSize: "cover",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
objectFit: "cover",
|
||||
backgroundImage: `url('${image}')`,
|
||||
}}
|
||||
/>
|
||||
<div style={{ padding: "16px", width: "100%" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "start",
|
||||
gap: "4px",
|
||||
color: theme === "dark" ? "white" : "inherit",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "baseline",
|
||||
gap: "4px",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 700,
|
||||
color: "rgb(107, 114, 128)",
|
||||
lineHeight: "18px",
|
||||
}}
|
||||
>
|
||||
{entry.data.title}
|
||||
</div>
|
||||
<span style={{ fontSize: "14px" }}>{`${date.getFullYear()}-${month < 10 ? `0${month}` : month}-${
|
||||
day < 10 ? `0${day}` : day
|
||||
}`}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
whiteSpace: "no-wrap",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
{hasLocalBackup ? (
|
||||
<div
|
||||
style={{
|
||||
border: "2px solid rgb(147, 197, 253)",
|
||||
borderRadius: "50%",
|
||||
color: "rgb(147, 197, 253)",
|
||||
height: "18px",
|
||||
width: "18px",
|
||||
fontWeight: "bold",
|
||||
fontSize: "11px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
textAlign: "center",
|
||||
}}
|
||||
title="Has local backup"
|
||||
>
|
||||
i
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: entry.data.draft === true ? "rgb(37, 99, 235)" : "rgb(22, 163, 74)",
|
||||
color: "white",
|
||||
border: "none",
|
||||
padding: "2px 6px",
|
||||
textAlign: "center",
|
||||
textDecoration: "none",
|
||||
display: "inline-block",
|
||||
cursor: "pointer",
|
||||
borderRadius: "4px",
|
||||
fontSize: "14px",
|
||||
}}
|
||||
>
|
||||
{entry.data.draft === true ? "Draft" : "Published"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const PostDateFieldPreview = ({ value }) => {
|
||||
const date = new Date(value);
|
||||
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
return <div>{`${date.getFullYear()}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`}</div>;
|
||||
};
|
||||
|
||||
const PostDraftFieldPreview = ({ value }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: value === true ? "rgb(37 99 235)" : "rgb(22 163 74)",
|
||||
color: "white",
|
||||
border: "none",
|
||||
padding: "2px 6px",
|
||||
textAlign: "center",
|
||||
textDecoration: "none",
|
||||
display: "inline-block",
|
||||
cursor: "pointer",
|
||||
borderRadius: "4px",
|
||||
fontSize: "14px",
|
||||
lineHeight: "16px",
|
||||
height: "20px",
|
||||
}}
|
||||
>
|
||||
{value === true ? "Draft" : "Published"}
|
||||
</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.registerPreviewTemplate("posts", PostPreview);
|
||||
CMS.registerPreviewCard("posts", PostPreviewCard, () => 240);
|
||||
CMS.registerFieldPreview("posts", "date", PostDateFieldPreview);
|
||||
CMS.registerFieldPreview("posts", "draft", PostDraftFieldPreview);
|
||||
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://staticcms.org",
|
||||
options: {
|
||||
icon: "page",
|
||||
},
|
||||
});
|
||||
cms.registerAdditionalLink({
|
||||
id: "config",
|
||||
title: "Demo config.yml",
|
||||
data: "https://github.com/StaticJsCMS/static-cms/blob/main/packages/demo/public/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>
|
||||
);
|
||||
},
|
||||
});
|
302
packages/demo/src/data.js
Normal file
302
packages/demo/src/data.js
Normal file
File diff suppressed because one or more lines are too long
14
packages/demo/src/editorial/index.html
Normal file
14
packages/demo/src/editorial/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Static CMS Demo - Editorial</title>
|
||||
<link rel="icon" type="image/png" href="/static-cms-icon.png" />
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<link href="/editorial/config.yml" type="text/yaml" rel="cms-config-url" />
|
||||
<script type="module" src="/index.jsx"></script>
|
||||
</body>
|
||||
</html>
|
201
packages/demo/src/index.html
Normal file
201
packages/demo/src/index.html
Normal file
File diff suppressed because one or more lines are too long
14
packages/demo/src/simple/index.html
Normal file
14
packages/demo/src/simple/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Static CMS Demo - Simple</title>
|
||||
<link rel="icon" type="image/png" href="/static-cms-icon.png" />
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<link href="/simple/config.yml" type="text/yaml" rel="cms-config-url" />
|
||||
<script type="module" src="/index.jsx"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,17 +1,48 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import svgrPlugin from "vite-plugin-svgr";
|
||||
import { defineConfig } from 'vite';
|
||||
import { resolve } from 'path';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import svgrPlugin from 'vite-plugin-svgr';
|
||||
|
||||
const root = resolve(__dirname, 'src');
|
||||
const publicDir = resolve(__dirname, 'public');
|
||||
const outDir = resolve(__dirname, 'build');
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), svgrPlugin()],
|
||||
assetsInclude: ["public/**/*"],
|
||||
root,
|
||||
publicDir,
|
||||
plugins: [
|
||||
react(),
|
||||
svgrPlugin(),
|
||||
{
|
||||
name: 'rewrite-middleware',
|
||||
configureServer(serve) {
|
||||
serve.middlewares.use((req, _res, next) => {
|
||||
if (req.url === '/simple') {
|
||||
req.url = '/simple/';
|
||||
} else if (req.url === '/editorial') {
|
||||
req.url = '/editorial/';
|
||||
}
|
||||
next();
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
assetsInclude: ['public/**/*'],
|
||||
optimizeDeps: {
|
||||
force: true,
|
||||
include: ["@staticcms/core"],
|
||||
include: ['@staticcms/core'],
|
||||
},
|
||||
build: {
|
||||
commonjsOptions: { include: [/core/, /node_modules/] },
|
||||
outDir: "build",
|
||||
outDir,
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
main: resolve(root, 'index.html'),
|
||||
simple: resolve(root, 'simple', 'index.html'),
|
||||
editorial: resolve(root, 'editorial', 'index.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
Reference in New Issue
Block a user