@brightsideoy/kama 0.1.0-alpha.37 ā 0.1.0-alpha.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +16 -8
- package/defaults/definitions/block-layouts/three-column.yaml +20 -0
- package/defaults/definitions/block-layouts/two-column.yaml +29 -0
- package/defaults/definitions/blocks/header.yaml +15 -0
- package/defaults/definitions/blocks/header_image.yaml +22 -0
- package/defaults/definitions/blocks/hero.yaml +27 -0
- package/defaults/definitions/blocks/image_card.yaml +53 -0
- package/defaults/definitions/blocks/text.yaml +16 -0
- package/defaults/definitions/channels/ecommerce.yaml +24 -0
- package/defaults/definitions/channels/website.yaml +32 -0
- package/defaults/definitions/field-sets/access.yaml +29 -0
- package/defaults/definitions/field-sets/channel-base.yaml +31 -0
- package/defaults/definitions/field-sets/comments.yaml +11 -0
- package/defaults/definitions/field-sets/content-block.yaml +46 -0
- package/defaults/definitions/field-sets/page-base.yaml +49 -0
- package/defaults/definitions/field-sets/page-meta.yaml +15 -0
- package/defaults/definitions/field-sets/page-social.yaml +80 -0
- package/defaults/definitions/field-sets/tree-base.yaml +31 -0
- package/defaults/definitions/field-sets/visibility.yaml +8 -0
- package/defaults/definitions/node-layouts/landing-page.yml +22 -0
- package/defaults/definitions/node-layouts/single-column.yml +38 -0
- package/defaults/definitions/node-layouts/three-column.yml +41 -0
- package/defaults/definitions/node-layouts/two-column.yml +40 -0
- package/defaults/definitions/nodes/address.yaml +32 -0
- package/defaults/definitions/nodes/article.yaml +41 -0
- package/defaults/definitions/nodes/event.yaml +40 -0
- package/defaults/definitions/nodes/external-link.yaml +26 -0
- package/defaults/definitions/nodes/page.yaml +63 -0
- package/defaults/definitions/nodes/person.yaml +35 -0
- package/defaults/definitions/nodes/product.yaml +79 -0
- package/defaults/definitions/trees/navigation.yaml +29 -0
- package/defaults/definitions/trees/social-links.yaml +9 -0
- package/definitions/_page.yaml +52 -0
- package/definitions/editor/default.ts +17 -0
- package/definitions/editor/header.ts +33 -0
- package/definitions/editor/minimal.ts +13 -0
- package/definitions/validators/iban.ts +12 -0
- package/definitions/validators/magic-word.ts +7 -0
- package/package.json +4 -1
- package/scripts/bundle-definitions.js +176 -0
package/bin/cli.js
CHANGED
|
@@ -42,6 +42,10 @@ async function createFullWorkspace() {
|
|
|
42
42
|
console.log(`\nš Creating workspace folder at ./${projName}...`);
|
|
43
43
|
mkdirSync(rootDir, { recursive: true });
|
|
44
44
|
|
|
45
|
+
// šÆ Scaffold schemas directory for custom project YAML definitions
|
|
46
|
+
mkdirSync(join(rootDir, 'schemas', 'nodes'), { recursive: true });
|
|
47
|
+
mkdirSync(join(rootDir, 'schemas', 'blocks'), { recursive: true });
|
|
48
|
+
|
|
45
49
|
// --- AUTO D1 CREATION MAGIC ---
|
|
46
50
|
let d1DatabaseId = 'REPLACE_WITH_YOUR_D1_ID';
|
|
47
51
|
let isAuthenticated = false;
|
|
@@ -112,7 +116,7 @@ async function createFullWorkspace() {
|
|
|
112
116
|
}
|
|
113
117
|
// ------------------------------
|
|
114
118
|
|
|
115
|
-
// 1. Root package.json
|
|
119
|
+
// šÆ 1. Root package.json with bundle:schemas hooked
|
|
116
120
|
writeFileSync(
|
|
117
121
|
join(rootDir, 'package.json'),
|
|
118
122
|
JSON.stringify({
|
|
@@ -121,18 +125,21 @@ async function createFullWorkspace() {
|
|
|
121
125
|
type: 'module',
|
|
122
126
|
workspaces: ['cms-worker', 'sites/*'],
|
|
123
127
|
scripts: {
|
|
124
|
-
'
|
|
125
|
-
'
|
|
128
|
+
'bundle:schemas': 'node node_modules/@brightsideoy/kama/scripts/bundle-definitions.js',
|
|
129
|
+
'dev:cms': 'npm run bundle:schemas && npm run dev -w cms-worker',
|
|
130
|
+
'deploy:cms': 'npm run bundle:schemas && npm run deploy -w cms-worker',
|
|
126
131
|
},
|
|
132
|
+
dependencies: {
|
|
133
|
+
'@brightsideoy/kama': 'alpha',
|
|
134
|
+
}
|
|
127
135
|
}, null, 2)
|
|
128
136
|
);
|
|
129
137
|
|
|
130
|
-
// 2. Setup CMS Worker
|
|
138
|
+
// šÆ 2. Setup CMS Worker
|
|
131
139
|
console.log(`\nāļø Configuring CMS Worker (${cmsDomain})...`);
|
|
132
140
|
const cmsDir = join(rootDir, 'cms-worker');
|
|
133
141
|
mkdirSync(cmsDir, { recursive: true });
|
|
134
142
|
|
|
135
|
-
// š The critical local entry point file!
|
|
136
143
|
writeFileSync(
|
|
137
144
|
join(cmsDir, 'index.js'),
|
|
138
145
|
`export { default } from '@brightsideoy/kama';\n`
|
|
@@ -145,8 +152,9 @@ async function createFullWorkspace() {
|
|
|
145
152
|
type: 'module',
|
|
146
153
|
version: '1.0.0',
|
|
147
154
|
scripts: {
|
|
148
|
-
"
|
|
149
|
-
"schema:
|
|
155
|
+
"bundle:schemas": "node ../node_modules/@brightsideoy/kama/scripts/bundle-definitions.js",
|
|
156
|
+
"schema:local": `npm run bundle:schemas && wrangler d1 execute ${dbName} --local --file=../node_modules/@brightsideoy/kama/schema.sql`,
|
|
157
|
+
"schema:remote": `npm run bundle:schemas && wrangler d1 execute ${dbName} --remote --file=../node_modules/@brightsideoy/kama/schema.sql`,
|
|
150
158
|
"dev": "npm run schema:local && wrangler dev",
|
|
151
159
|
"deploy": "npm run schema:remote && wrangler deploy"
|
|
152
160
|
},
|
|
@@ -165,7 +173,7 @@ async function createFullWorkspace() {
|
|
|
165
173
|
JSON.stringify({
|
|
166
174
|
$schema: '../node_modules/wrangler/config-schema.json',
|
|
167
175
|
name: 'kama-worker',
|
|
168
|
-
main: 'index.js',
|
|
176
|
+
main: 'index.js',
|
|
169
177
|
compatibility_date: '2026-08-01',
|
|
170
178
|
compatibility_flags: ['nodejs_compat'],
|
|
171
179
|
assets: {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
id: three-column
|
|
2
|
+
label: Three Columns (33/33/33)
|
|
3
|
+
showLabel: false
|
|
4
|
+
group: Sub-Layouts
|
|
5
|
+
|
|
6
|
+
layout:
|
|
7
|
+
columns: "1fr 1fr 1fr"
|
|
8
|
+
areas:
|
|
9
|
+
- ["left", "middle", "right"]
|
|
10
|
+
|
|
11
|
+
regions:
|
|
12
|
+
left:
|
|
13
|
+
label: Left Column
|
|
14
|
+
showLabel: false # š Hides "LEFT COLUMN" header on this region cell
|
|
15
|
+
middle:
|
|
16
|
+
label: Middle Column
|
|
17
|
+
showLabel: false # š Hides "LEFT COLUMN" header on this region cell
|
|
18
|
+
right:
|
|
19
|
+
label: Right Column
|
|
20
|
+
showLabel: false # š Keeps "RIGHT COLUMN" visible
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: two-column
|
|
2
|
+
label: Two Columns (50/50)
|
|
3
|
+
showLabel: false # š Hides the main "Two Columns" badge on the canvas
|
|
4
|
+
group: Sub-Layouts
|
|
5
|
+
|
|
6
|
+
layout:
|
|
7
|
+
columns: "1fr 1fr"
|
|
8
|
+
areas:
|
|
9
|
+
- ["left", "right"]
|
|
10
|
+
|
|
11
|
+
regions:
|
|
12
|
+
left:
|
|
13
|
+
label: Left Column
|
|
14
|
+
showLabel: false # š Hides "LEFT COLUMN" header on this region cell
|
|
15
|
+
right:
|
|
16
|
+
label: Right Column
|
|
17
|
+
showLabel: false # š Keeps "RIGHT COLUMN" visible
|
|
18
|
+
|
|
19
|
+
# Optional: We can give the layout block its own settings!
|
|
20
|
+
fields:
|
|
21
|
+
gap:
|
|
22
|
+
label: Column Gap
|
|
23
|
+
type: select
|
|
24
|
+
default: "2rem"
|
|
25
|
+
options:
|
|
26
|
+
- { label: "None", value: "0" }
|
|
27
|
+
- { label: "Small", value: "1rem" }
|
|
28
|
+
- { label: "Medium", value: "2rem" }
|
|
29
|
+
- { label: "Large", value: "4rem" }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: header_image
|
|
2
|
+
label: Header Image
|
|
3
|
+
group: Content
|
|
4
|
+
description: Image for page header.
|
|
5
|
+
|
|
6
|
+
fields:
|
|
7
|
+
- image:
|
|
8
|
+
label: Image
|
|
9
|
+
type: asset
|
|
10
|
+
required: true
|
|
11
|
+
multiple: false
|
|
12
|
+
maxSizeMB: 15
|
|
13
|
+
allowedTypes: ["image/*"]
|
|
14
|
+
crops:
|
|
15
|
+
standard:
|
|
16
|
+
label: "Page header (21:9)"
|
|
17
|
+
aspectRatio: 2.333
|
|
18
|
+
public: true
|
|
19
|
+
|
|
20
|
+
- fieldSet: access
|
|
21
|
+
- hidden:
|
|
22
|
+
default: false
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
id: hero
|
|
2
|
+
label: Hero
|
|
3
|
+
group: Content
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
- heroBadge:
|
|
7
|
+
type: text
|
|
8
|
+
label: Badge
|
|
9
|
+
public: true
|
|
10
|
+
- heroTitle:
|
|
11
|
+
type: text
|
|
12
|
+
label: Title
|
|
13
|
+
public: true
|
|
14
|
+
- heroSubTitle:
|
|
15
|
+
type: text
|
|
16
|
+
label: Sub-Title
|
|
17
|
+
public: true
|
|
18
|
+
- headline:
|
|
19
|
+
type: richtext
|
|
20
|
+
editor: header
|
|
21
|
+
label: Headline
|
|
22
|
+
public: true
|
|
23
|
+
default: "Header here..."
|
|
24
|
+
|
|
25
|
+
- fieldSet: access
|
|
26
|
+
- hidden:
|
|
27
|
+
default: false
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
id: image_card
|
|
2
|
+
label: Image Card
|
|
3
|
+
Group: Content
|
|
4
|
+
description: A versatile card with an image, text, and a CTA button.
|
|
5
|
+
|
|
6
|
+
fields:
|
|
7
|
+
- image:
|
|
8
|
+
label: Card Image
|
|
9
|
+
showLabel: false
|
|
10
|
+
type: asset
|
|
11
|
+
required: true
|
|
12
|
+
multiple: false
|
|
13
|
+
maxSizeMB: 15
|
|
14
|
+
maxPreviewWidth: 300px
|
|
15
|
+
allowedTypes: ["image/*"]
|
|
16
|
+
crops:
|
|
17
|
+
standard:
|
|
18
|
+
label: "Card Header (16:9)"
|
|
19
|
+
aspectRatio: 3.0
|
|
20
|
+
public: true
|
|
21
|
+
|
|
22
|
+
- headline:
|
|
23
|
+
label: Headline
|
|
24
|
+
type: text
|
|
25
|
+
required: true
|
|
26
|
+
public: true
|
|
27
|
+
default: "Headline..."
|
|
28
|
+
|
|
29
|
+
- summary:
|
|
30
|
+
label: Text
|
|
31
|
+
description: Keep it brief, 2-3 sentences max.
|
|
32
|
+
type: richtext
|
|
33
|
+
editor: minimal
|
|
34
|
+
public: true
|
|
35
|
+
default: "Card text content..."
|
|
36
|
+
|
|
37
|
+
- linkUrl:
|
|
38
|
+
label: Link URL
|
|
39
|
+
type: text
|
|
40
|
+
description: Where should this card link to? (e.g., /about or https://...)
|
|
41
|
+
public: true
|
|
42
|
+
default: "https://"
|
|
43
|
+
|
|
44
|
+
- linkText:
|
|
45
|
+
label: Button Text
|
|
46
|
+
type: text
|
|
47
|
+
description: "e.g., 'Read More' or 'Buy Now'"
|
|
48
|
+
default: "Read More"
|
|
49
|
+
public: true
|
|
50
|
+
|
|
51
|
+
- fieldSet: access
|
|
52
|
+
- hidden:
|
|
53
|
+
default: false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
id: text
|
|
2
|
+
label: Text
|
|
3
|
+
group: Content
|
|
4
|
+
description: Paragraph body
|
|
5
|
+
|
|
6
|
+
fields:
|
|
7
|
+
- body:
|
|
8
|
+
label: Text
|
|
9
|
+
type: richtext
|
|
10
|
+
editor: default
|
|
11
|
+
default: "Write content here..."
|
|
12
|
+
public: true
|
|
13
|
+
|
|
14
|
+
- fieldSet: access
|
|
15
|
+
- hidden:
|
|
16
|
+
default: false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
id: ecommerce
|
|
2
|
+
label: "E-Commerce"
|
|
3
|
+
|
|
4
|
+
tabs:
|
|
5
|
+
settings:
|
|
6
|
+
label: "Channel"
|
|
7
|
+
fields:
|
|
8
|
+
- fieldSet: channel-base
|
|
9
|
+
|
|
10
|
+
- currency:
|
|
11
|
+
label: Default Currency
|
|
12
|
+
type: select
|
|
13
|
+
default: "EUR"
|
|
14
|
+
options:
|
|
15
|
+
- "EUR"
|
|
16
|
+
- "USD"
|
|
17
|
+
- "GBP"
|
|
18
|
+
|
|
19
|
+
- checkoutUrl:
|
|
20
|
+
label: Checkout Endpoint URL
|
|
21
|
+
type: text
|
|
22
|
+
public: true
|
|
23
|
+
|
|
24
|
+
- fieldSet: access
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: website
|
|
2
|
+
label: "Website"
|
|
3
|
+
|
|
4
|
+
tabs:
|
|
5
|
+
settings:
|
|
6
|
+
label: "Channel"
|
|
7
|
+
fields:
|
|
8
|
+
- fieldSet: channel-base
|
|
9
|
+
|
|
10
|
+
- domain:
|
|
11
|
+
label: Hostname
|
|
12
|
+
type: text
|
|
13
|
+
dbType: text
|
|
14
|
+
index: true
|
|
15
|
+
public: true
|
|
16
|
+
|
|
17
|
+
- baseUrl:
|
|
18
|
+
label: Base URL
|
|
19
|
+
type: text
|
|
20
|
+
dbType: text
|
|
21
|
+
public: true
|
|
22
|
+
|
|
23
|
+
- defaultLanguage:
|
|
24
|
+
label: Channel Language / Locale
|
|
25
|
+
type: language-select
|
|
26
|
+
dbType: text
|
|
27
|
+
public: true
|
|
28
|
+
|
|
29
|
+
access:
|
|
30
|
+
label: "Access"
|
|
31
|
+
fields:
|
|
32
|
+
- fieldSet: access
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
tab:
|
|
2
|
+
id: access
|
|
3
|
+
label: "Access"
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
isHidden: # šÆ Renamed from 'hidden' to match the DB column
|
|
7
|
+
type: boolean
|
|
8
|
+
label: Hidden
|
|
9
|
+
default: false
|
|
10
|
+
public: false
|
|
11
|
+
variant: danger
|
|
12
|
+
dbType: integer
|
|
13
|
+
index: true
|
|
14
|
+
position: sidebar
|
|
15
|
+
liveSync: true
|
|
16
|
+
|
|
17
|
+
startShowingAt:
|
|
18
|
+
type: datetime
|
|
19
|
+
label: Start Showing At
|
|
20
|
+
position: sidebar
|
|
21
|
+
public: false
|
|
22
|
+
index: true
|
|
23
|
+
|
|
24
|
+
stopShowingAt:
|
|
25
|
+
type: datetime
|
|
26
|
+
label: Stop Showing At
|
|
27
|
+
position: sidebar
|
|
28
|
+
public: false
|
|
29
|
+
index: true
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: channel-base
|
|
2
|
+
label: Channel Base Properties
|
|
3
|
+
|
|
4
|
+
fields:
|
|
5
|
+
- id:
|
|
6
|
+
label: Internal ID
|
|
7
|
+
type: hidden
|
|
8
|
+
dbType: integer
|
|
9
|
+
primaryKey: true
|
|
10
|
+
|
|
11
|
+
- label:
|
|
12
|
+
label: Channel Name
|
|
13
|
+
type: text
|
|
14
|
+
dbType: text
|
|
15
|
+
public: true
|
|
16
|
+
rules:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- key:
|
|
20
|
+
label: "API Identifier"
|
|
21
|
+
type: slug
|
|
22
|
+
dbType: text
|
|
23
|
+
public: true
|
|
24
|
+
index: true
|
|
25
|
+
linkedTo: label
|
|
26
|
+
placeholder: "e.g. main-site, store-eu"
|
|
27
|
+
rules:
|
|
28
|
+
required: true
|
|
29
|
+
unique: true
|
|
30
|
+
pattern: "^[a-z0-9-_]+$"
|
|
31
|
+
customMessage: "API key must be unique and contain only lowercase letters, numbers, hyphens, or underscores."
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# definitions/field-sets/content-block.yaml
|
|
2
|
+
id: content-block
|
|
3
|
+
label: Content Block Base Properties
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
- id:
|
|
7
|
+
label: ID
|
|
8
|
+
type: hidden
|
|
9
|
+
dbType: text
|
|
10
|
+
primaryKey: true
|
|
11
|
+
|
|
12
|
+
- contentId:
|
|
13
|
+
label: Node ID
|
|
14
|
+
type: text
|
|
15
|
+
dbType: text
|
|
16
|
+
rules:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- sortOrder:
|
|
20
|
+
label: Sort Order
|
|
21
|
+
type: number
|
|
22
|
+
dbType: integer
|
|
23
|
+
rules:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- elementType:
|
|
27
|
+
label: Element Component Type
|
|
28
|
+
type: text
|
|
29
|
+
dbType: text
|
|
30
|
+
rules:
|
|
31
|
+
required: true
|
|
32
|
+
|
|
33
|
+
- dataJson:
|
|
34
|
+
label: Content Field Data
|
|
35
|
+
type: json
|
|
36
|
+
dbType: json
|
|
37
|
+
rules:
|
|
38
|
+
required: true
|
|
39
|
+
|
|
40
|
+
- region:
|
|
41
|
+
label: Grid Region
|
|
42
|
+
type: text
|
|
43
|
+
dbType: text
|
|
44
|
+
default: "main"
|
|
45
|
+
rules:
|
|
46
|
+
required: true
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# definitions/field-sets/page-base.yaml
|
|
2
|
+
id: page-base
|
|
3
|
+
label: Base Page Properties
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
- id:
|
|
7
|
+
label: ID
|
|
8
|
+
type: hidden
|
|
9
|
+
dbType: text
|
|
10
|
+
primaryKey: true
|
|
11
|
+
public: true
|
|
12
|
+
|
|
13
|
+
- channelId:
|
|
14
|
+
label: Channel ID
|
|
15
|
+
type: hidden
|
|
16
|
+
dbType: text
|
|
17
|
+
public: true
|
|
18
|
+
index: true
|
|
19
|
+
|
|
20
|
+
- nodeType:
|
|
21
|
+
label: Type
|
|
22
|
+
type: select
|
|
23
|
+
dbType: text
|
|
24
|
+
default: "page"
|
|
25
|
+
public: true
|
|
26
|
+
position: sidebar
|
|
27
|
+
rules:
|
|
28
|
+
required: true
|
|
29
|
+
|
|
30
|
+
- title:
|
|
31
|
+
label: Page Title
|
|
32
|
+
type: text
|
|
33
|
+
dbType: text
|
|
34
|
+
public: true
|
|
35
|
+
rules:
|
|
36
|
+
required: true
|
|
37
|
+
|
|
38
|
+
- slug:
|
|
39
|
+
label: URL Slug
|
|
40
|
+
type: slug
|
|
41
|
+
linkedTo: title
|
|
42
|
+
dbType: text
|
|
43
|
+
public: true
|
|
44
|
+
index: true
|
|
45
|
+
rules:
|
|
46
|
+
required: true
|
|
47
|
+
uniqueSibling: true
|
|
48
|
+
pattern: "^[a-z0-9_-]+$"
|
|
49
|
+
customMessage: "Slug can only contain lowercase letters, numbers, hyphens, and underscores."
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
tab:
|
|
2
|
+
id: page-social
|
|
3
|
+
label: "Social"
|
|
4
|
+
|
|
5
|
+
fields:
|
|
6
|
+
# --- Facebook / Open Graph Texts ---
|
|
7
|
+
fbTitle:
|
|
8
|
+
label: "Facebook Title (og:title)"
|
|
9
|
+
type: text
|
|
10
|
+
inherits: title # š Syncs from SEO Title automatically
|
|
11
|
+
public: true
|
|
12
|
+
description: "The title of your article as it should appear on Facebook."
|
|
13
|
+
|
|
14
|
+
fbDescription:
|
|
15
|
+
label: "Facebook Description (og:description)"
|
|
16
|
+
type: textarea
|
|
17
|
+
inherits: metaDescription # š Or whatever your main SEO description field is named
|
|
18
|
+
public: true
|
|
19
|
+
description: "A 2-4 sentence summary of the content."
|
|
20
|
+
|
|
21
|
+
# --- X (Twitter) Texts ---
|
|
22
|
+
xTitle:
|
|
23
|
+
label: "X Title (twitter:title)"
|
|
24
|
+
type: text
|
|
25
|
+
inherits: fbTitle # š Cascades from Facebook Title (which cascades from SEO)
|
|
26
|
+
public: true
|
|
27
|
+
description: "Keep it concise (under 70 characters is ideal for X)."
|
|
28
|
+
|
|
29
|
+
xDescription:
|
|
30
|
+
label: "X Description (twitter:description)"
|
|
31
|
+
type: textarea
|
|
32
|
+
inherits: fbDescription
|
|
33
|
+
public: true
|
|
34
|
+
|
|
35
|
+
# ==========================================
|
|
36
|
+
# SOCIAL IMAGES (The Waterfall)
|
|
37
|
+
# ==========================================
|
|
38
|
+
|
|
39
|
+
# 1. The Source Image
|
|
40
|
+
socialImage:
|
|
41
|
+
label: "Master Social Image"
|
|
42
|
+
type: image
|
|
43
|
+
maxPreviewWidth: 620px
|
|
44
|
+
multiple: false
|
|
45
|
+
maxSizeMB: 10
|
|
46
|
+
allowedTypes: ["image/jpeg", "image/png", "image/webp"]
|
|
47
|
+
public: true
|
|
48
|
+
|
|
49
|
+
# 2. The Auto-Synced Crops
|
|
50
|
+
fbImage:
|
|
51
|
+
label: "Facebook / LinkedIn Image"
|
|
52
|
+
type: image
|
|
53
|
+
maxPreviewWidth: 620px
|
|
54
|
+
inherits: socialImage # š Syncs from socialImage
|
|
55
|
+
public: true
|
|
56
|
+
description: "Auto-cropped to 1.91:1. Drop a new image here to override."
|
|
57
|
+
crops:
|
|
58
|
+
aspectRatio: 1.91
|
|
59
|
+
|
|
60
|
+
xImage:
|
|
61
|
+
label: "X (Twitter) Image"
|
|
62
|
+
type: image
|
|
63
|
+
maxPreviewWidth: 620px
|
|
64
|
+
inherits: socialImage # š Syncs from socialImage
|
|
65
|
+
public: true
|
|
66
|
+
description: "Auto-cropped to 2:1. Drop a new image here to override."
|
|
67
|
+
crops:
|
|
68
|
+
aspectRatio: 2.0
|
|
69
|
+
|
|
70
|
+
whatsappImage:
|
|
71
|
+
label: "Messaging / Square Image"
|
|
72
|
+
type: image
|
|
73
|
+
maxPreviewWidth: 620px
|
|
74
|
+
inherits: socialImage # š Syncs from socialImage
|
|
75
|
+
public: true
|
|
76
|
+
description: "Auto-cropped to 1:1. Drop a new image here to override."
|
|
77
|
+
crops:
|
|
78
|
+
whatsappImage:
|
|
79
|
+
label: "WhatsApp Image (1:1)"
|
|
80
|
+
aspectRatio: 1.0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
id: tree-base
|
|
2
|
+
label: Tree Base Properties
|
|
3
|
+
|
|
4
|
+
fields:
|
|
5
|
+
- id:
|
|
6
|
+
label: Internal ID
|
|
7
|
+
type: hidden
|
|
8
|
+
dbType: integer
|
|
9
|
+
primaryKey: true
|
|
10
|
+
|
|
11
|
+
- label:
|
|
12
|
+
label: "Label"
|
|
13
|
+
type: text
|
|
14
|
+
dbType: text
|
|
15
|
+
public: true
|
|
16
|
+
rules:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- key:
|
|
20
|
+
label: "API Identifier"
|
|
21
|
+
type: slug
|
|
22
|
+
dbType: text
|
|
23
|
+
index: true
|
|
24
|
+
public: true
|
|
25
|
+
linkedTo: label
|
|
26
|
+
placeholder: "e.g. main-site, store-eu"
|
|
27
|
+
rules:
|
|
28
|
+
required: true
|
|
29
|
+
unique: true
|
|
30
|
+
pattern: "^[a-z0-9-_]+$"
|
|
31
|
+
customMessage: "API key must be unique and contain only lowercase letters, numbers, hyphens, or underscores."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
id: landing-page
|
|
2
|
+
label: Landing Page
|
|
3
|
+
|
|
4
|
+
layout:
|
|
5
|
+
columns: "1fr"
|
|
6
|
+
areas:
|
|
7
|
+
- ["header"]
|
|
8
|
+
- ["hero"]
|
|
9
|
+
- ["content"]
|
|
10
|
+
- ["footer"]
|
|
11
|
+
|
|
12
|
+
regions:
|
|
13
|
+
header:
|
|
14
|
+
label: Header
|
|
15
|
+
inherit: parent
|
|
16
|
+
hero:
|
|
17
|
+
label: Hero / Top Banner
|
|
18
|
+
content:
|
|
19
|
+
label: Content
|
|
20
|
+
footer:
|
|
21
|
+
label: Footer
|
|
22
|
+
inherit: parent
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
id: single-column
|
|
2
|
+
label: Single Column
|
|
3
|
+
|
|
4
|
+
layout:
|
|
5
|
+
columns: "1fr"
|
|
6
|
+
areas:
|
|
7
|
+
- ["header"]
|
|
8
|
+
- ["content"]
|
|
9
|
+
- ["footer"]
|
|
10
|
+
|
|
11
|
+
regions:
|
|
12
|
+
header:
|
|
13
|
+
label: Header Image
|
|
14
|
+
showLabel: true
|
|
15
|
+
inherit: parent
|
|
16
|
+
allowOverride: true
|
|
17
|
+
dropType: image
|
|
18
|
+
maxPreviewWidth: 800px
|
|
19
|
+
multiple: false
|
|
20
|
+
maxSizeMB: 20
|
|
21
|
+
allowedTypes: ["image/*"]
|
|
22
|
+
crops:
|
|
23
|
+
standard:
|
|
24
|
+
label: "Desktop Header (4:1)"
|
|
25
|
+
aspectRatio: 4.0
|
|
26
|
+
tablet:
|
|
27
|
+
label: "Tablet Header (2:1)"
|
|
28
|
+
aspectRatio: 2.0
|
|
29
|
+
mobile:
|
|
30
|
+
label: "Mobile Header (4:3)"
|
|
31
|
+
aspectRatio: 1.33
|
|
32
|
+
public: true
|
|
33
|
+
|
|
34
|
+
content:
|
|
35
|
+
label: Content
|
|
36
|
+
footer:
|
|
37
|
+
label: Footer
|
|
38
|
+
inherit: parent
|