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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -24,27 +24,6 @@ const PostDateFieldPreview = ({ value }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const PostDraftFieldPreview = ({ value }) => {
|
||||
return h(
|
||||
'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',
|
||||
},
|
||||
},
|
||||
value === true ? 'Draft' : 'Published',
|
||||
);
|
||||
};
|
||||
|
||||
const GeneralPreview = ({ widgetsFor, entry, collection }) => {
|
||||
const title = entry.data.site_title;
|
||||
const posts = entry.data.posts;
|
||||
@ -88,38 +67,16 @@ const AuthorsPreview = ({ widgetsFor }) => {
|
||||
);
|
||||
};
|
||||
|
||||
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.registerPreviewTemplate('posts', PostPreview);
|
||||
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.registerWidget('relationKitchenSinkPost', 'relation');
|
||||
CMS.registerAdditionalLink({
|
||||
id: 'example',
|
||||
title: 'Example.com',
|
||||
@ -152,7 +109,9 @@ CMS.registerShortcode('youtube', {
|
||||
toArgs: ({ src }) => {
|
||||
return [src];
|
||||
},
|
||||
control: ({ src, onChange, theme }) => {
|
||||
control: ({ src, onChange }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return h('span', {}, [
|
||||
h('input', {
|
||||
key: 'control-input',
|
||||
@ -162,8 +121,8 @@ CMS.registerShortcode('youtube', {
|
||||
},
|
||||
style: {
|
||||
width: '100%',
|
||||
backgroundColor: theme === 'dark' ? 'rgb(30, 41, 59)' : 'white',
|
||||
color: theme === 'dark' ? 'white' : 'black',
|
||||
backgroundColor: theme.common.gray,
|
||||
color: theme.text.primary,
|
||||
padding: '4px 8px',
|
||||
},
|
||||
}),
|
||||
|
@ -1,6 +1,5 @@
|
||||
---
|
||||
title: Something something something2...
|
||||
draft: false
|
||||
date: 2022-11-01 06:30
|
||||
image: static-cms-icon.svg
|
||||
---
|
||||
|
@ -1,6 +1,5 @@
|
||||
---
|
||||
title: Test
|
||||
draft: false
|
||||
date: 2022-11-01 14:28
|
||||
image: kittens.jpg
|
||||
---
|
||||
|
@ -1,6 +1,5 @@
|
||||
---
|
||||
title: Test3
|
||||
draft: false
|
||||
date: 2022-11-02 08:43
|
||||
image: ori_3587884_d966kldqzc6mvdeq67hyk16rnbe3gb1k8eeoy31s_shark-icon.jpg
|
||||
---
|
||||
|
File diff suppressed because it is too large
Load Diff
1598
packages/core/dev-test/backends/test/config.yml
Normal file
1598
packages/core/dev-test/backends/test/config.yml
Normal file
File diff suppressed because it is too large
Load Diff
13
packages/core/dev-test/backends/test/index.html
Normal file
13
packages/core/dev-test/backends/test/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>Static CMS Development Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="/static-cms-core.js"></script>
|
||||
<script src="/data.js"></script>
|
||||
<script type="module" src="/index.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,8 +1,7 @@
|
||||
backend:
|
||||
name: test-repo
|
||||
site_url: 'https://example.com'
|
||||
media_folder: assets/uploads
|
||||
public_folder: /assets/uploads
|
||||
media_folder: /assets/uploads
|
||||
media_library:
|
||||
folder_support: true
|
||||
locale: en
|
||||
@ -18,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
|
||||
@ -31,7 +30,6 @@ collections:
|
||||
summary_fields:
|
||||
- title
|
||||
- date
|
||||
- draft
|
||||
sortable_fields:
|
||||
fields:
|
||||
- title
|
||||
@ -40,28 +38,35 @@ 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
|
||||
- name: draft
|
||||
label: Drafts
|
||||
field: draft
|
||||
pattern: true
|
||||
view_groups:
|
||||
- label: Year
|
||||
field: date
|
||||
pattern: '\d{4}'
|
||||
- label: Drafts
|
||||
field: draft
|
||||
groups:
|
||||
- name: by-year
|
||||
label: Year
|
||||
field: date
|
||||
pattern: '\d{4}'
|
||||
- name: draft
|
||||
label: Drafts
|
||||
field: draft
|
||||
fields:
|
||||
- label: Title
|
||||
name: title
|
||||
widget: string
|
||||
- label: Draft
|
||||
name: draft
|
||||
widget: boolean
|
||||
- label: 'Draft'
|
||||
name: 'draft'
|
||||
widget: 'boolean'
|
||||
default: false
|
||||
- label: Publish Date
|
||||
name: date
|
||||
@ -73,10 +78,19 @@ collections:
|
||||
name: image
|
||||
widget: image
|
||||
required: false
|
||||
- label: Description
|
||||
name: description
|
||||
widget: text
|
||||
- label: Category
|
||||
name: category
|
||||
widget: string
|
||||
- label: Body
|
||||
name: body
|
||||
widget: markdown
|
||||
hint: "*Main* __content__ __*goes*__ [here](https://example.com/)."
|
||||
hint: '*Main* __content__ __*goes*__ [here](https://example.com/).'
|
||||
- label: Tags
|
||||
name: tags
|
||||
widget: list
|
||||
- name: faq
|
||||
label: FAQ
|
||||
folder: _faqs
|
||||
@ -150,6 +164,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
|
||||
@ -571,6 +598,7 @@ collections:
|
||||
- label: Type 2 Object
|
||||
name: type_2_object
|
||||
widget: object
|
||||
summary: "{{datetime | date('yyyy-MM-dd')}}"
|
||||
fields:
|
||||
- label: Number
|
||||
name: number
|
||||
@ -778,6 +806,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
|
||||
@ -1055,6 +1096,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
|
||||
@ -1099,11 +1153,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
|
||||
@ -1142,6 +1191,34 @@ collections:
|
||||
- label: Description
|
||||
name: description
|
||||
widget: text
|
||||
- name: hotels
|
||||
label: Hotel Locations
|
||||
file: _data/hotel_locations.yml
|
||||
fields:
|
||||
- name: country
|
||||
label: Country
|
||||
widget: string
|
||||
- name: hotel_locations
|
||||
label: Hotel Locations
|
||||
widget: list
|
||||
fields:
|
||||
- name: cities
|
||||
label: Cities
|
||||
widget: list
|
||||
fields:
|
||||
- name: city
|
||||
label: City
|
||||
widget: string
|
||||
- name: number_of_hotels_in_city
|
||||
label: Number of Hotels in City
|
||||
widget: number
|
||||
- name: city_locations
|
||||
label: City Locations
|
||||
widget: list
|
||||
fields:
|
||||
- name: hotel_name
|
||||
label: Hotel Name
|
||||
widget: string
|
||||
- name: kitchenSink
|
||||
label: Kitchen Sink
|
||||
folder: _sink
|
||||
|
308
packages/core/dev-test/data.js
Normal file
308
packages/core/dev-test/data.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -11,134 +11,6 @@ const PostPreview = ({ entry, widgetFor }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const PostPreviewCard = ({ entry, theme, hasLocalBackup, collection }) => {
|
||||
const date = new Date(entry.data.date);
|
||||
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
const imageField = useMemo(() => collection.fields.find((f) => f.name === 'image'), []);
|
||||
const image = useMediaAsset(entry.data.image, collection, imageField, entry);
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{ style: { width: '100%' } },
|
||||
h('div', {
|
||||
style: {
|
||||
width: '100%',
|
||||
borderTopLeftRadius: '8px',
|
||||
borderTopRightRadius: '8px',
|
||||
overflow: 'hidden',
|
||||
height: '140px',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
objectFit: 'cover',
|
||||
backgroundImage: `url('${image}')`,
|
||||
},
|
||||
}),
|
||||
h(
|
||||
'div',
|
||||
{ style: { padding: '16px', width: '100%' } },
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'start',
|
||||
gap: '4px',
|
||||
color: theme === 'dark' ? 'white' : 'inherit',
|
||||
},
|
||||
},
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'baseline',
|
||||
gap: '4px',
|
||||
},
|
||||
},
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
fontSize: '14px',
|
||||
fontWeight: 700,
|
||||
color: 'rgb(107, 114, 128)',
|
||||
lineHeight: '18px',
|
||||
},
|
||||
},
|
||||
entry.data.title,
|
||||
),
|
||||
h(
|
||||
'span',
|
||||
{ style: { fontSize: '14px' } },
|
||||
`${date.getFullYear()}-${month < 10 ? `0${month}` : month}-${
|
||||
day < 10 ? `0${day}` : day
|
||||
}`,
|
||||
),
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
whiteSpace: 'no-wrap',
|
||||
gap: '8px',
|
||||
},
|
||||
},
|
||||
hasLocalBackup
|
||||
? h(
|
||||
'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',
|
||||
)
|
||||
: null,
|
||||
h(
|
||||
'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',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const PostDateFieldPreview = ({ value }) => {
|
||||
const date = new Date(value);
|
||||
|
||||
@ -152,29 +24,6 @@ const PostDateFieldPreview = ({ value }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const PostDraftFieldPreview = ({ value }) => {
|
||||
return h(
|
||||
'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',
|
||||
);
|
||||
};
|
||||
|
||||
const GeneralPreview = ({ widgetsFor, entry, collection }) => {
|
||||
const title = entry.data.site_title;
|
||||
const posts = entry.data.posts;
|
||||
@ -218,39 +67,16 @@ const AuthorsPreview = ({ widgetsFor }) => {
|
||||
);
|
||||
};
|
||||
|
||||
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.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.registerWidget('relationKitchenSinkPost', 'relation');
|
||||
CMS.registerAdditionalLink({
|
||||
id: 'example',
|
||||
title: 'Example.com',
|
||||
@ -268,6 +94,14 @@ CMS.registerAdditionalLink({
|
||||
},
|
||||
});
|
||||
|
||||
CMS.registerTheme({
|
||||
name: 'Custom Red Orange',
|
||||
extends: 'dark',
|
||||
primary: {
|
||||
main: '#ff4500',
|
||||
}
|
||||
});
|
||||
|
||||
CMS.registerShortcode('youtube', {
|
||||
label: 'YouTube',
|
||||
openTag: '[',
|
||||
@ -283,7 +117,9 @@ CMS.registerShortcode('youtube', {
|
||||
toArgs: ({ src }) => {
|
||||
return [src];
|
||||
},
|
||||
control: ({ src, onChange, theme }) => {
|
||||
control: ({ src, onChange }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return h('span', {}, [
|
||||
h('input', {
|
||||
key: 'control-input',
|
||||
@ -293,8 +129,8 @@ CMS.registerShortcode('youtube', {
|
||||
},
|
||||
style: {
|
||||
width: '100%',
|
||||
backgroundColor: theme === 'dark' ? 'rgb(30, 41, 59)' : 'white',
|
||||
color: theme === 'dark' ? 'white' : 'black',
|
||||
backgroundColor: theme.common.gray,
|
||||
color: theme.text.primary,
|
||||
padding: '4px 8px',
|
||||
},
|
||||
}),
|
||||
|
Reference in New Issue
Block a user