RustyCMS: File-based headless CMS with REST API, admin UI, multilingual support
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
48
types/blog_post.json5
Normal file
48
types/blog_post.json5
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
name: "blog_post",
|
||||
description: "Simple blog post with title, body, tags and publish status",
|
||||
tags: ["content", "blog"],
|
||||
category: "content",
|
||||
fields: {
|
||||
title: {
|
||||
type: "string",
|
||||
required: true,
|
||||
minLength: 1,
|
||||
maxLength: 200,
|
||||
description: "Title of the blog post",
|
||||
},
|
||||
body: {
|
||||
type: "markdown",
|
||||
required: true,
|
||||
minLength: 1,
|
||||
description: "Main content (Markdown)",
|
||||
},
|
||||
excerpt: {
|
||||
type: "string",
|
||||
maxLength: 500,
|
||||
description: "Short summary for previews",
|
||||
},
|
||||
author: {
|
||||
type: "string",
|
||||
description: "Author name"
|
||||
},
|
||||
tags: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
},
|
||||
description: "Categorisation tags"
|
||||
},
|
||||
published: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Whether the post is publicly visible"
|
||||
},
|
||||
created_at: {
|
||||
type: "datetime",
|
||||
auto: true,
|
||||
readonly: true,
|
||||
description: "Creation timestamp (auto-generated)"
|
||||
},
|
||||
}
|
||||
}
|
||||
61
types/campaign.json5
Normal file
61
types/campaign.json5
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
// Corresponds to CF_Campaign / Contentful_Campaign.ts
|
||||
name: "campaign",
|
||||
description: "Campaign with URL pattern and optional content",
|
||||
tags: ["marketing", "config"],
|
||||
category: "config",
|
||||
fields: {
|
||||
campaignName: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Campaign name",
|
||||
},
|
||||
urlPattern: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "URL pattern (e.g. regex) for campaign usage",
|
||||
},
|
||||
selector: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "CSS selector where content is inserted",
|
||||
},
|
||||
insertHtml: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: [
|
||||
"afterbegin",
|
||||
"beforeend",
|
||||
"afterend",
|
||||
"beforebegin",
|
||||
"replace"
|
||||
],
|
||||
default: "beforeend",
|
||||
description: "Position relative to selector",
|
||||
},
|
||||
timeUntil: {
|
||||
type: "datetime",
|
||||
description: "Time limit (until when the campaign runs)",
|
||||
},
|
||||
javascript: {
|
||||
type: "string",
|
||||
description: "Optional JavaScript",
|
||||
},
|
||||
medias: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
},
|
||||
description: "Media (images)",
|
||||
},
|
||||
html: {
|
||||
type: "html",
|
||||
description: "HTML content",
|
||||
},
|
||||
css: {
|
||||
type: "string",
|
||||
description: "Optional CSS",
|
||||
},
|
||||
},
|
||||
}
|
||||
27
types/campaigns.json5
Normal file
27
types/campaigns.json5
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
// Corresponds to CF_Campaigns / Contentful_Campaigns.ts
|
||||
name: "campaigns",
|
||||
description: "Global campaign list and enable flag",
|
||||
tags: ["marketing", "config"],
|
||||
category: "config",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique ID (e.g. campaigns-global)",
|
||||
},
|
||||
campaigns: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "campaign",
|
||||
},
|
||||
description: "Campaign list",
|
||||
},
|
||||
enable: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Campaigns enabled",
|
||||
},
|
||||
},
|
||||
}
|
||||
33
types/component_layout.json5
Normal file
33
types/component_layout.json5
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
// Reusable partial (CF_ComponentLayout) – no own collection.
|
||||
name: "component_layout",
|
||||
description: "Reusable grid layout (mobile/tablet/desktop columns)",
|
||||
tags: ["layout", "partial"],
|
||||
category: "layout",
|
||||
reusable: true,
|
||||
fields: {
|
||||
mobile: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
||||
default: "12",
|
||||
description: "Width on mobile (1–12)",
|
||||
},
|
||||
tablet: {
|
||||
type: "string",
|
||||
enum: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
||||
description: "Width on tablet (optional)",
|
||||
},
|
||||
desktop: {
|
||||
type: "string",
|
||||
enum: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
|
||||
description: "Width on desktop (optional)",
|
||||
},
|
||||
spaceBottom: {
|
||||
type: "number",
|
||||
enum: [0, 0.5, 1, 1.5, 2],
|
||||
default: 0,
|
||||
description: "Space below (rem)",
|
||||
},
|
||||
},
|
||||
}
|
||||
141
types/content_layout.json5
Normal file
141
types/content_layout.json5
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
// Equivalent to: CF_Content interface
|
||||
// Base type for pages/posts with a 3-row content layout
|
||||
name: "content_layout",
|
||||
description: "Base layout with 3 content rows (inherited by page, post, etc.)",
|
||||
tags: ["layout", "partial"],
|
||||
category: "layout",
|
||||
fields: {
|
||||
row1JustifyContent: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"between",
|
||||
"around",
|
||||
"evenly"
|
||||
],
|
||||
default: "start",
|
||||
description: "Justify content for row 1",
|
||||
},
|
||||
row1AlignItems: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"baseline",
|
||||
"stretch"
|
||||
],
|
||||
default: "stretch",
|
||||
description: "Align items for row 1",
|
||||
},
|
||||
row1Content: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collections: [
|
||||
"markdown",
|
||||
"html",
|
||||
"headline",
|
||||
"image",
|
||||
"quote",
|
||||
"youtube_video",
|
||||
"image_gallery",
|
||||
"iframe",
|
||||
"searchable_text",
|
||||
"fullwidth_banner",
|
||||
"list"
|
||||
],
|
||||
},
|
||||
description: "Content components for row 1 (Markdown, HTML, Headline, Image, …)",
|
||||
},
|
||||
row2JustifyContent: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"between",
|
||||
"around",
|
||||
"evenly"
|
||||
],
|
||||
default: "start",
|
||||
},
|
||||
row2AlignItems: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"baseline",
|
||||
"stretch"
|
||||
],
|
||||
default: "stretch",
|
||||
},
|
||||
row2Content: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collections: [
|
||||
"markdown",
|
||||
"html",
|
||||
"headline",
|
||||
"image",
|
||||
"quote",
|
||||
"youtube_video",
|
||||
"image_gallery",
|
||||
"iframe",
|
||||
"searchable_text",
|
||||
"fullwidth_banner",
|
||||
"list"
|
||||
],
|
||||
},
|
||||
description: "Content components for row 2",
|
||||
},
|
||||
row3JustifyContent: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"between",
|
||||
"around",
|
||||
"evenly"
|
||||
],
|
||||
default: "start",
|
||||
},
|
||||
row3AlignItems: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"start",
|
||||
"end",
|
||||
"center",
|
||||
"baseline",
|
||||
"stretch"
|
||||
],
|
||||
default: "stretch",
|
||||
},
|
||||
row3Content: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collections: [
|
||||
"markdown",
|
||||
"html",
|
||||
"headline",
|
||||
"image",
|
||||
"quote",
|
||||
"youtube_video",
|
||||
"image_gallery",
|
||||
"iframe",
|
||||
"searchable_text",
|
||||
"fullwidth_banner",
|
||||
"list"
|
||||
],
|
||||
},
|
||||
description: "Content components for row 3",
|
||||
},
|
||||
}
|
||||
}
|
||||
17
types/footer.json5
Normal file
17
types/footer.json5
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
// Corresponds to CF_Footer extends CF_Content / Contentful_Footer.ts
|
||||
name: "footer",
|
||||
description: "Footer with content layout",
|
||||
tags: ["layout", "config"],
|
||||
category: "config",
|
||||
extends: [
|
||||
"content_layout"
|
||||
],
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique footer ID (e.g. for navigation)",
|
||||
},
|
||||
},
|
||||
}
|
||||
39
types/fullwidth_banner.json5
Normal file
39
types/fullwidth_banner.json5
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
// Equivalent to: CF_FullwidthBanner interface
|
||||
name: "fullwidth_banner",
|
||||
description: "Full-width banner with dark/light variant",
|
||||
tags: ["component", "layout"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal name"
|
||||
},
|
||||
variant: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: ["dark", "light"],
|
||||
default: "light",
|
||||
description: "Color variant"
|
||||
},
|
||||
headline: {
|
||||
type: "string",
|
||||
required: true
|
||||
},
|
||||
subheadline: {
|
||||
type: "string"
|
||||
},
|
||||
text: {
|
||||
type: "richtext",
|
||||
description: "Banner body text"
|
||||
},
|
||||
image: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
},
|
||||
description: "Image URLs"
|
||||
},
|
||||
}
|
||||
}
|
||||
37
types/headline.json5
Normal file
37
types/headline.json5
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentHeadline / Contentful_Headline.ts
|
||||
name: "headline",
|
||||
description: "Headline component with optional layout",
|
||||
tags: ["component", "layout"],
|
||||
category: "components",
|
||||
fields: {
|
||||
internal: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal key",
|
||||
},
|
||||
text: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Headline text",
|
||||
},
|
||||
tag: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
||||
default: "h2",
|
||||
description: "HTML tag for headline",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
align: {
|
||||
type: "string",
|
||||
enum: ["left", "center", "right"],
|
||||
default: "left",
|
||||
description: "Text alignment",
|
||||
},
|
||||
},
|
||||
}
|
||||
24
types/html.json5
Normal file
24
types/html.json5
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
// Corresponds to CF_HTML / Contentful_Html.ts
|
||||
name: "html",
|
||||
description: "Raw HTML content block with optional layout",
|
||||
tags: ["content", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique component ID",
|
||||
},
|
||||
html: {
|
||||
type: "html",
|
||||
required: true,
|
||||
description: "HTML content (safely embedded)",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
},
|
||||
}
|
||||
34
types/iframe.json5
Normal file
34
types/iframe.json5
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentIframe / Contentful_Iframe.ts
|
||||
name: "iframe",
|
||||
description: "Embedded iframe with URL and optional title",
|
||||
tags: ["media", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal component name",
|
||||
},
|
||||
content: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Description/content for iframe",
|
||||
},
|
||||
iframe: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Iframe URL or embed code",
|
||||
},
|
||||
overlayImage: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
description: "Optional overlay image (reference to img)",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
},
|
||||
}
|
||||
37
types/image.json5
Normal file
37
types/image.json5
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentImage / Contentful_Image.ts
|
||||
name: "image",
|
||||
description: "Image component with reference to img asset and layout",
|
||||
tags: ["component", "media"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal component name",
|
||||
},
|
||||
image: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
required: true,
|
||||
description: "Image (reference to img)",
|
||||
},
|
||||
caption: {
|
||||
type: "string",
|
||||
description: "Image caption",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
maxWidth: {
|
||||
type: "integer",
|
||||
description: "Max width in px",
|
||||
},
|
||||
aspectRatio: {
|
||||
type: "number",
|
||||
description: "Aspect ratio (e.g. 16/9)",
|
||||
},
|
||||
},
|
||||
}
|
||||
32
types/image_gallery.json5
Normal file
32
types/image_gallery.json5
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
// Corresponds to CF_ImageGallery / Contentful_ImageGallery.ts
|
||||
name: "image_gallery",
|
||||
description: "Gallery of image references",
|
||||
tags: ["media", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal gallery name",
|
||||
},
|
||||
images: {
|
||||
type: "array",
|
||||
required: true,
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
},
|
||||
description: "Images (references to img)",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
description: "Optional gallery description",
|
||||
},
|
||||
},
|
||||
}
|
||||
56
types/img.json5
Normal file
56
types/img.json5
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentImg / Contentful_Img.ts (Asset/Image)
|
||||
name: "img",
|
||||
description: "Image asset with URL, filename and optional dimensions",
|
||||
tags: ["asset", "media"],
|
||||
category: "components",
|
||||
fields: {
|
||||
title: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Image title",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
description: "Alt text / description",
|
||||
},
|
||||
file: {
|
||||
type: "object",
|
||||
required: true,
|
||||
description: "File: url (required), fileName, contentType, details (size, image.width/height)",
|
||||
fields: {
|
||||
url: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Image file URL",
|
||||
},
|
||||
fileName: {
|
||||
type: "string",
|
||||
description: "Filename",
|
||||
},
|
||||
contentType: {
|
||||
type: "string",
|
||||
description: "e.g. image/jpeg",
|
||||
},
|
||||
details: {
|
||||
type: "object",
|
||||
description: "Size and dimensions",
|
||||
fields: {
|
||||
size: {
|
||||
type: "integer",
|
||||
description: "File size in bytes",
|
||||
},
|
||||
image: {
|
||||
type: "object",
|
||||
description: "Image dimensions",
|
||||
fields: {
|
||||
width: { type: "integer", description: "Width in px" },
|
||||
height: { type: "integer", description: "Height in px" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
75
types/link.json5
Normal file
75
types/link.json5
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
// Corresponds to CF_Link / Contentful_Link.ts
|
||||
name: "link",
|
||||
description: "Internal or external link with label and optional icon",
|
||||
tags: ["navigation", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal link name",
|
||||
},
|
||||
internal: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal key",
|
||||
},
|
||||
linkName: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Display name (e.g. in navigation)",
|
||||
},
|
||||
url: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Target URL",
|
||||
},
|
||||
icon: {
|
||||
type: "string",
|
||||
description: "Icon identifier",
|
||||
},
|
||||
color: {
|
||||
type: "string",
|
||||
description: "Color (e.g. for buttons)",
|
||||
},
|
||||
newTab: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Open in new tab",
|
||||
},
|
||||
external: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "External link",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
description: "Description",
|
||||
},
|
||||
alt: {
|
||||
type: "string",
|
||||
description: "Alt text (e.g. for icon)",
|
||||
},
|
||||
showText: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Show text",
|
||||
},
|
||||
author: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Author (e.g. for sources)",
|
||||
},
|
||||
date: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Date (e.g. publication)",
|
||||
},
|
||||
source: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Source",
|
||||
},
|
||||
},
|
||||
}
|
||||
23
types/link_list.json5
Normal file
23
types/link_list.json5
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
// Corresponds to CF_Link_List / Contentful_Link_List.ts (componentLinkList)
|
||||
name: "link_list",
|
||||
description: "List of links with optional headline",
|
||||
tags: ["navigation", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
headline: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Link list headline",
|
||||
},
|
||||
links: {
|
||||
type: "array",
|
||||
required: true,
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "link",
|
||||
},
|
||||
description: "Links (references to link)",
|
||||
},
|
||||
},
|
||||
}
|
||||
20
types/list.json5
Normal file
20
types/list.json5
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentList / Contentful_List.ts
|
||||
name: "list",
|
||||
description: "Simple list of string items",
|
||||
tags: ["content", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
internal: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal key",
|
||||
},
|
||||
item: {
|
||||
type: "array",
|
||||
required: true,
|
||||
items: { type: "string" },
|
||||
description: "List entries",
|
||||
},
|
||||
},
|
||||
}
|
||||
29
types/markdown.json5
Normal file
29
types/markdown.json5
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
// Corresponds to CF_Markdown / Contentful_Markdown.ts
|
||||
name: "markdown",
|
||||
description: "Markdown content block with optional layout",
|
||||
tags: ["content", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal component name",
|
||||
},
|
||||
content: {
|
||||
type: "markdown",
|
||||
description: "Markdown/body text content",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
alignment: {
|
||||
type: "string",
|
||||
enum: ["left", "center", "right"],
|
||||
default: "left",
|
||||
description: "Text alignment",
|
||||
},
|
||||
},
|
||||
}
|
||||
28
types/navigation.json5
Normal file
28
types/navigation.json5
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
// Corresponds to CF_Navigation / Contentful_Navigation.ts
|
||||
name: "navigation",
|
||||
description: "Navigation block with links (header/footer)",
|
||||
tags: ["navigation", "layout"],
|
||||
category: "config",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Display name of navigation",
|
||||
},
|
||||
internal: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal key (e.g. navigation-header, navigation-footer)",
|
||||
},
|
||||
links: {
|
||||
type: "array",
|
||||
required: true,
|
||||
items: {
|
||||
type: "reference",
|
||||
collections: ["link", "page", "post"],
|
||||
},
|
||||
description: "Navigation entries (references to link, page or post)",
|
||||
},
|
||||
},
|
||||
}
|
||||
45
types/page.json5
Normal file
45
types/page.json5
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
// Equivalent to: CF_Page extends CF_Content, CF_SEO
|
||||
name: "page",
|
||||
description: "Page with layout, SEO and content rows",
|
||||
tags: ["content", "page"],
|
||||
category: "content",
|
||||
extends: [
|
||||
"content_layout",
|
||||
"seo"
|
||||
],
|
||||
fields: {
|
||||
slug: {
|
||||
type: "string",
|
||||
required: true,
|
||||
unique: true,
|
||||
description: "URL slug"
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Internal page name"
|
||||
},
|
||||
linkName: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Display name in navigation"
|
||||
},
|
||||
icon: {
|
||||
type: "string",
|
||||
description: "Icon identifier (optional)"
|
||||
},
|
||||
headline: {
|
||||
type: "string",
|
||||
required: true
|
||||
},
|
||||
subheadline: {
|
||||
type: "string"
|
||||
},
|
||||
topFullwidthBanner: {
|
||||
type: "reference",
|
||||
collection: "fullwidth_banner",
|
||||
description: "Hero banner at the top"
|
||||
},
|
||||
}
|
||||
}
|
||||
47
types/page_config.json5
Normal file
47
types/page_config.json5
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
// Corresponds to CF_PageConfig / Contentful_PageConfig.ts
|
||||
name: "page_config",
|
||||
description: "Global page config (logo, footer, etc.)",
|
||||
tags: ["config", "layout"],
|
||||
category: "config",
|
||||
fields: {
|
||||
logo: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
required: true,
|
||||
description: "Logo image (reference to img)",
|
||||
},
|
||||
footerText1: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Footer text (e.g. copyright)",
|
||||
},
|
||||
seoTitle: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Default SEO title for website",
|
||||
},
|
||||
seoDescription: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Default meta description",
|
||||
},
|
||||
blogTagPageHeadline: {
|
||||
type: "string",
|
||||
description: "Headline for tag page (blog)",
|
||||
},
|
||||
blogPostsPageHeadline: {
|
||||
type: "string",
|
||||
description: "Headline for blog overview page",
|
||||
},
|
||||
blogPostsPageSubHeadline: {
|
||||
type: "string",
|
||||
description: "Subheadline for blog overview page",
|
||||
},
|
||||
website: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Website-URL",
|
||||
},
|
||||
},
|
||||
}
|
||||
75
types/post.json5
Normal file
75
types/post.json5
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
// Equivalent to: CF_Post extends CF_Content, CF_SEO
|
||||
name: "post",
|
||||
description: "Blog post with layout, SEO and optional tags",
|
||||
tags: ["content", "blog"],
|
||||
category: "content",
|
||||
extends: [
|
||||
"content_layout",
|
||||
"seo"
|
||||
],
|
||||
fields: {
|
||||
slug: {
|
||||
type: "string",
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
linkName: {
|
||||
type: "string",
|
||||
required: true
|
||||
},
|
||||
icon: {
|
||||
type: "string"
|
||||
},
|
||||
headline: {
|
||||
type: "string",
|
||||
required: true
|
||||
},
|
||||
subheadline: {
|
||||
type: "string"
|
||||
},
|
||||
excerpt: {
|
||||
type: "string",
|
||||
maxLength: 500,
|
||||
description: "Short summary for previews"
|
||||
},
|
||||
created: {
|
||||
type: "datetime",
|
||||
auto: true,
|
||||
readonly: true
|
||||
},
|
||||
postImage: {
|
||||
type: "reference",
|
||||
collection: "img",
|
||||
description: "Featured image"
|
||||
},
|
||||
postTag: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "tag"
|
||||
},
|
||||
description: "Associated tags"
|
||||
},
|
||||
important: {
|
||||
type: "boolean",
|
||||
required: true,
|
||||
default: false,
|
||||
description: "Mark post as important"
|
||||
},
|
||||
date: {
|
||||
type: "datetime",
|
||||
description: "Optional display date"
|
||||
},
|
||||
content: {
|
||||
type: "markdown",
|
||||
required: true,
|
||||
description: "Post body (Markdown)"
|
||||
},
|
||||
showCommentSection: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Show comment section (default: true)"
|
||||
},
|
||||
}
|
||||
}
|
||||
62
types/post_overview.json5
Normal file
62
types/post_overview.json5
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
// Corresponds to CF_Post_Overview / Contentful_Post_Overview.ts (extends CF_Content, CF_SEO)
|
||||
name: "post_overview",
|
||||
description: "Post listing page with layout and SEO",
|
||||
tags: ["content", "blog"],
|
||||
category: "content",
|
||||
extends: [
|
||||
"content_layout",
|
||||
"seo"
|
||||
],
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique post overview ID",
|
||||
},
|
||||
headline: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Headline",
|
||||
},
|
||||
text: {
|
||||
type: "richtext",
|
||||
description: "Intro text",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid)",
|
||||
},
|
||||
allPosts: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Show all posts (otherwise filter)",
|
||||
},
|
||||
filterByTag: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "tag",
|
||||
},
|
||||
description: "Only posts with these tags",
|
||||
},
|
||||
posts: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "post",
|
||||
},
|
||||
description: "Fixed list of posts (when not allPosts)",
|
||||
},
|
||||
numberItems: {
|
||||
type: "integer",
|
||||
description: "Max. number of displayed entries",
|
||||
},
|
||||
design: {
|
||||
type: "string",
|
||||
enum: ["cards", "list"],
|
||||
description: "Display as cards or list",
|
||||
},
|
||||
},
|
||||
}
|
||||
73
types/product.json5
Normal file
73
types/product.json5
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
// Showcases: strict mode, constraints, unique, nullable, readonly, pattern
|
||||
name: "product",
|
||||
description: "Product with SKU, price and optional fields (strict schema)",
|
||||
tags: ["content", "ecommerce"],
|
||||
category: "content",
|
||||
strict: true,
|
||||
fields: {
|
||||
title: {
|
||||
type: "string",
|
||||
required: true,
|
||||
minLength: 1,
|
||||
maxLength: 200,
|
||||
description: "Product name",
|
||||
},
|
||||
sku: {
|
||||
type: "string",
|
||||
required: true,
|
||||
unique: true,
|
||||
pattern: "^[A-Z]{2,4}-\\d{3,6}$",
|
||||
description: "Stock Keeping Unit (e.g. EL-1234, BOOK-00042)",
|
||||
},
|
||||
price: {
|
||||
type: "number",
|
||||
required: true,
|
||||
min: 0,
|
||||
description: "Price in EUR",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
maxLength: 5000,
|
||||
description: "Detailed product description",
|
||||
},
|
||||
category: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: [
|
||||
"electronics",
|
||||
"clothing",
|
||||
"books",
|
||||
"food",
|
||||
"other"
|
||||
],
|
||||
description: "Product category",
|
||||
},
|
||||
in_stock: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
description: "Whether the product is in stock"
|
||||
},
|
||||
rating: {
|
||||
type: "number",
|
||||
min: 0,
|
||||
max: 5,
|
||||
nullable: true,
|
||||
description: "Average customer rating (null if unrated)"
|
||||
},
|
||||
images: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
},
|
||||
minItems: 1,
|
||||
maxItems: 10,
|
||||
description: "Product image URLs (1–10)",
|
||||
},
|
||||
created_at: {
|
||||
type: "datetime",
|
||||
auto: true,
|
||||
readonly: true
|
||||
},
|
||||
}
|
||||
}
|
||||
31
types/quote.json5
Normal file
31
types/quote.json5
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
// Corresponds to CF_Quote / Contentful_Quote.ts
|
||||
name: "quote",
|
||||
description: "Quote block with author and optional variant",
|
||||
tags: ["content", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
quote: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Quote text",
|
||||
},
|
||||
author: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Author or source of quote",
|
||||
},
|
||||
variant: {
|
||||
type: "string",
|
||||
required: true,
|
||||
enum: ["left", "right"],
|
||||
default: "left",
|
||||
description: "Quote alignment",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
},
|
||||
}
|
||||
44
types/searchable_text.json5
Normal file
44
types/searchable_text.json5
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
// Corresponds to CF_ComponentSearchableText / Contentful_SearchableText.ts
|
||||
name: "searchable_text",
|
||||
description: "Searchable text with optional tag whitelist",
|
||||
tags: ["content", "component", "search"],
|
||||
category: "components",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique component ID",
|
||||
},
|
||||
tagWhitelist: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "tag",
|
||||
},
|
||||
description: "Optional: only search content with these tags",
|
||||
},
|
||||
textFragments: {
|
||||
type: "array",
|
||||
required: true,
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "text_fragment",
|
||||
},
|
||||
description: "Searchable text fragments (references to text_fragment)",
|
||||
},
|
||||
title: {
|
||||
type: "string",
|
||||
description: "Search component title",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
description: "Description",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
},
|
||||
}
|
||||
30
types/seo.json5
Normal file
30
types/seo.json5
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
// Equivalent to: CF_SEO interface
|
||||
name: "seo",
|
||||
description: "SEO meta (title, robots, description; inherited by page/post)",
|
||||
tags: ["seo", "partial"],
|
||||
category: "layout",
|
||||
fields: {
|
||||
seoTitle: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "SEO page title"
|
||||
},
|
||||
seoMetaRobots: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"index, follow",
|
||||
"noindex, follow",
|
||||
"index, nofollow",
|
||||
"noindex, nofollow"
|
||||
],
|
||||
default: "index, follow",
|
||||
description: "Robots meta directive",
|
||||
},
|
||||
seoDescription: {
|
||||
type: "string",
|
||||
maxLength: 160,
|
||||
description: "Meta description for search engines"
|
||||
},
|
||||
}
|
||||
}
|
||||
14
types/tag.json5
Normal file
14
types/tag.json5
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
// Equivalent to: CF_Tag interface
|
||||
name: "tag",
|
||||
description: "Tag for categorising content",
|
||||
tags: ["taxonomy", "config"],
|
||||
category: "config",
|
||||
fields: {
|
||||
name: {
|
||||
type: "string",
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
}
|
||||
}
|
||||
32
types/text_fragment.json5
Normal file
32
types/text_fragment.json5
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
// Corresponds to CF_TextFragment / Contentful_TextFragment.ts
|
||||
name: "text_fragment",
|
||||
description: "Reusable text fragment with optional tag references",
|
||||
tags: ["content", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique fragment ID",
|
||||
},
|
||||
tags: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "reference",
|
||||
collection: "tag",
|
||||
},
|
||||
description: "Optional tags for categorisation",
|
||||
},
|
||||
title: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Text fragment title",
|
||||
},
|
||||
text: {
|
||||
type: "richtext",
|
||||
required: true,
|
||||
description: "Searchable text content",
|
||||
},
|
||||
},
|
||||
}
|
||||
19
types/top_banner.json5
Normal file
19
types/top_banner.json5
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
// Corresponds to CF_TopBanner / Contentful_TopBanner.ts
|
||||
name: "top_banner",
|
||||
description: "Top-of-page banner or notice text",
|
||||
tags: ["component", "layout"],
|
||||
category: "components",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Unique ID",
|
||||
},
|
||||
text: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "Banner text (e.g. notice at top of page)",
|
||||
},
|
||||
},
|
||||
}
|
||||
35
types/youtube_video.json5
Normal file
35
types/youtube_video.json5
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
// Corresponds to CF_YoutubeVideo / Contentful_YoutubeVideo.ts
|
||||
name: "youtube_video",
|
||||
description: "Embedded YouTube video with optional params",
|
||||
tags: ["media", "component"],
|
||||
category: "components",
|
||||
fields: {
|
||||
id: {
|
||||
type: "string",
|
||||
description: "Unique ID (optional, otherwise _slug)",
|
||||
},
|
||||
youtubeId: {
|
||||
type: "string",
|
||||
required: true,
|
||||
description: "YouTube video ID (e.g. from URL ?v=VIDEO_ID)",
|
||||
},
|
||||
params: {
|
||||
type: "string",
|
||||
description: "Optional URL params (e.g. start=30, autoplay=1)",
|
||||
},
|
||||
title: {
|
||||
type: "string",
|
||||
description: "Video title",
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
description: "Short description",
|
||||
},
|
||||
layout: {
|
||||
type: "object",
|
||||
useFields: "component_layout",
|
||||
description: "Column width (grid) like CF_ComponentLayout",
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user