@brightsideoy/kama 0.1.0-alpha.39 → 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/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 +3 -1
- package/scripts/bundle-definitions.js +40 -16
|
@@ -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
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
id: three-column
|
|
2
|
+
label: Three Column
|
|
3
|
+
|
|
4
|
+
layout:
|
|
5
|
+
columns: "2fr 7fr 3fr"
|
|
6
|
+
areas:
|
|
7
|
+
- ["header", "header", "header"]
|
|
8
|
+
- ["left_nav", "content", "right_sidebar"]
|
|
9
|
+
- ["footer", "footer", "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
|
+
left_nav:
|
|
34
|
+
label: Left Navigation
|
|
35
|
+
content:
|
|
36
|
+
label: Content
|
|
37
|
+
right_sidebar:
|
|
38
|
+
label: Right Sidebar
|
|
39
|
+
footer:
|
|
40
|
+
label: Footer
|
|
41
|
+
inherit: parent
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# defaults/definitions/layouts/two-column-split.yml
|
|
2
|
+
id: two-column
|
|
3
|
+
label: Two Column
|
|
4
|
+
|
|
5
|
+
layout:
|
|
6
|
+
columns: "10fr 4fr"
|
|
7
|
+
areas:
|
|
8
|
+
- ["header", "header"]
|
|
9
|
+
- ["content", "sidebar"] # 👈 Changed 'main' to 'content' to match old data!
|
|
10
|
+
- ["footer", "footer"]
|
|
11
|
+
|
|
12
|
+
regions:
|
|
13
|
+
header:
|
|
14
|
+
label: Header Image
|
|
15
|
+
showLabel: true
|
|
16
|
+
inherit: parent
|
|
17
|
+
allowOverride: true
|
|
18
|
+
dropType: image
|
|
19
|
+
maxPreviewWidth: 800px
|
|
20
|
+
multiple: false
|
|
21
|
+
maxSizeMB: 20
|
|
22
|
+
allowedTypes: ["image/*"]
|
|
23
|
+
crops:
|
|
24
|
+
standard:
|
|
25
|
+
label: "Desktop Header (4:1)"
|
|
26
|
+
aspectRatio: 4.0
|
|
27
|
+
tablet:
|
|
28
|
+
label: "Tablet Header (2:1)"
|
|
29
|
+
aspectRatio: 2.0
|
|
30
|
+
mobile:
|
|
31
|
+
label: "Mobile Header (4:3)"
|
|
32
|
+
aspectRatio: 1.33
|
|
33
|
+
public: true
|
|
34
|
+
content: # 👈 Changed 'main' to 'content'
|
|
35
|
+
label: Content
|
|
36
|
+
sidebar:
|
|
37
|
+
label: Sidebar
|
|
38
|
+
footer:
|
|
39
|
+
label: Footer
|
|
40
|
+
inherit: parent
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
id: address
|
|
2
|
+
label: Address
|
|
3
|
+
inTree: false
|
|
4
|
+
|
|
5
|
+
# 👉 TABS DEFINITION
|
|
6
|
+
tabs:
|
|
7
|
+
settings:
|
|
8
|
+
label: "Address"
|
|
9
|
+
fields:
|
|
10
|
+
- title:
|
|
11
|
+
label: Address Title
|
|
12
|
+
required: true
|
|
13
|
+
- street:
|
|
14
|
+
label: Street
|
|
15
|
+
- city:
|
|
16
|
+
label: City
|
|
17
|
+
- area:
|
|
18
|
+
label: County / Area
|
|
19
|
+
- zip:
|
|
20
|
+
label: ZIP
|
|
21
|
+
- country:
|
|
22
|
+
label: Country
|
|
23
|
+
geolocation:
|
|
24
|
+
label: "Geolocation"
|
|
25
|
+
fields:
|
|
26
|
+
- lat:
|
|
27
|
+
label: Latitude
|
|
28
|
+
- lng:
|
|
29
|
+
label: Longitude
|
|
30
|
+
- timezone:
|
|
31
|
+
label: Timezone
|
|
32
|
+
- fieldSet: access
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
id: article
|
|
2
|
+
label: Article
|
|
3
|
+
inTree: false
|
|
4
|
+
hasCanvas: true
|
|
5
|
+
|
|
6
|
+
regions:
|
|
7
|
+
content:
|
|
8
|
+
label: Content
|
|
9
|
+
|
|
10
|
+
allowedElements:
|
|
11
|
+
- header
|
|
12
|
+
- hero
|
|
13
|
+
- text
|
|
14
|
+
- image_card
|
|
15
|
+
- header_image
|
|
16
|
+
- two-column
|
|
17
|
+
- three-column
|
|
18
|
+
|
|
19
|
+
tabs:
|
|
20
|
+
settings:
|
|
21
|
+
label: "Article"
|
|
22
|
+
fields:
|
|
23
|
+
- fieldSet: page-base
|
|
24
|
+
- title:
|
|
25
|
+
label: Article title
|
|
26
|
+
required: true
|
|
27
|
+
- slug:
|
|
28
|
+
linkedTo: "title"
|
|
29
|
+
- articleDate:
|
|
30
|
+
type: date
|
|
31
|
+
label: Article Date
|
|
32
|
+
public: true
|
|
33
|
+
default: now
|
|
34
|
+
index: true
|
|
35
|
+
- abstract:
|
|
36
|
+
label: Abstract
|
|
37
|
+
type: textarea
|
|
38
|
+
public: true
|
|
39
|
+
- fieldSet: page-meta
|
|
40
|
+
- fieldSet: page-social
|
|
41
|
+
- fieldSet: access
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
id: event
|
|
2
|
+
label: Event
|
|
3
|
+
inTree: false
|
|
4
|
+
hasCanvas: true
|
|
5
|
+
|
|
6
|
+
regions:
|
|
7
|
+
main:
|
|
8
|
+
label: Content
|
|
9
|
+
|
|
10
|
+
allowedElements:
|
|
11
|
+
- title-set
|
|
12
|
+
- text-block
|
|
13
|
+
|
|
14
|
+
tabs:
|
|
15
|
+
settings:
|
|
16
|
+
label: Event
|
|
17
|
+
fields:
|
|
18
|
+
- fieldSet: page-base
|
|
19
|
+
- title:
|
|
20
|
+
label: Event Title
|
|
21
|
+
required: true
|
|
22
|
+
- slug:
|
|
23
|
+
linkedTo: "title"
|
|
24
|
+
- startTime:
|
|
25
|
+
type: datetime
|
|
26
|
+
label: Starts
|
|
27
|
+
public: true
|
|
28
|
+
index: true
|
|
29
|
+
- endTime:
|
|
30
|
+
type: datetime
|
|
31
|
+
label: Finishes
|
|
32
|
+
public: true
|
|
33
|
+
index: true
|
|
34
|
+
- abstract:
|
|
35
|
+
label: Abstract
|
|
36
|
+
type: textarea
|
|
37
|
+
public: true
|
|
38
|
+
- fieldSet: page-meta
|
|
39
|
+
- fieldSet: page-social
|
|
40
|
+
- fieldSet: access
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: external-link
|
|
2
|
+
label: External Link
|
|
3
|
+
inTree: true
|
|
4
|
+
|
|
5
|
+
tabs:
|
|
6
|
+
settings:
|
|
7
|
+
label: "Link"
|
|
8
|
+
fields:
|
|
9
|
+
- fieldSet: page-base
|
|
10
|
+
- nodeType
|
|
11
|
+
- title:
|
|
12
|
+
label: Link Text
|
|
13
|
+
- iconName:
|
|
14
|
+
label: Icon
|
|
15
|
+
type: icon
|
|
16
|
+
dbType: text
|
|
17
|
+
packages: ["heroicons", "lucide", "mdi"]
|
|
18
|
+
- slug:
|
|
19
|
+
label: Slug
|
|
20
|
+
linkedTo: "menuTitle, title"
|
|
21
|
+
- url:
|
|
22
|
+
label: URL
|
|
23
|
+
type: text
|
|
24
|
+
public: true
|
|
25
|
+
|
|
26
|
+
- fieldSet: access
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
id: page
|
|
2
|
+
label: Page
|
|
3
|
+
inTree: true
|
|
4
|
+
inVault: true
|
|
5
|
+
hasCanvas: true
|
|
6
|
+
|
|
7
|
+
# 👈 Keep this as the absolute last-resort fallback for the Public API
|
|
8
|
+
defaultLayout: "single-column"
|
|
9
|
+
|
|
10
|
+
# 👈 Cleaned up naming!
|
|
11
|
+
allowedBlocks:
|
|
12
|
+
- header
|
|
13
|
+
- hero
|
|
14
|
+
- text
|
|
15
|
+
- image_card
|
|
16
|
+
- header_image
|
|
17
|
+
- two-column
|
|
18
|
+
- three-column
|
|
19
|
+
|
|
20
|
+
tabs:
|
|
21
|
+
settings:
|
|
22
|
+
label: "Page"
|
|
23
|
+
fields:
|
|
24
|
+
- fieldSet: page-base
|
|
25
|
+
|
|
26
|
+
# 👉 THE CURRENT PAGE'S LAYOUT
|
|
27
|
+
- layoutId:
|
|
28
|
+
label: Page Layout
|
|
29
|
+
type: layout-select
|
|
30
|
+
dbType: text
|
|
31
|
+
default: "inherit"
|
|
32
|
+
inheritsFromParent: true # 👈 Tells the UI to bind to the parent!
|
|
33
|
+
allowedLayouts:
|
|
34
|
+
- two-column
|
|
35
|
+
- single-column
|
|
36
|
+
- three-column
|
|
37
|
+
- landing-page
|
|
38
|
+
options:
|
|
39
|
+
- { label: "Inherit Layout", value: "inherit" }
|
|
40
|
+
|
|
41
|
+
# 👉 THE BEHAVIOR FOR ALL CHILDREN
|
|
42
|
+
- subpageLayoutId:
|
|
43
|
+
label: Subpages Layout Rule
|
|
44
|
+
type: layout-select
|
|
45
|
+
dbType: text
|
|
46
|
+
default: "inherit"
|
|
47
|
+
inheritsFromParent: true # 👈 A child's subpage rules can ALSO inherit!
|
|
48
|
+
allowedLayouts:
|
|
49
|
+
- two-column
|
|
50
|
+
- three-column
|
|
51
|
+
- single-column
|
|
52
|
+
- landing-page
|
|
53
|
+
options:
|
|
54
|
+
- { label: "Inherit Layout", value: "inherit" }
|
|
55
|
+
|
|
56
|
+
- menuTitle:
|
|
57
|
+
label: Menu Title
|
|
58
|
+
type: text
|
|
59
|
+
dbType: text
|
|
60
|
+
public: true
|
|
61
|
+
- fieldSet: page-meta
|
|
62
|
+
- fieldSet: page-social
|
|
63
|
+
- fieldSet: access
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
id: person
|
|
2
|
+
label: Person
|
|
3
|
+
inTree: false
|
|
4
|
+
inVault: true
|
|
5
|
+
hasCanvas: false
|
|
6
|
+
|
|
7
|
+
# 👉 TABS DEFINITION
|
|
8
|
+
tabs:
|
|
9
|
+
settings:
|
|
10
|
+
label: "Person"
|
|
11
|
+
fields:
|
|
12
|
+
- image:
|
|
13
|
+
label: Image
|
|
14
|
+
type: asset
|
|
15
|
+
multiple: false
|
|
16
|
+
maxSizeMB: 15
|
|
17
|
+
allowedTypes: ["image/*"]
|
|
18
|
+
maxPreviewWidth: 300
|
|
19
|
+
crops:
|
|
20
|
+
list_thumb:
|
|
21
|
+
label: "List View"
|
|
22
|
+
aspectRatio: 1
|
|
23
|
+
shape: "circle"
|
|
24
|
+
public: true
|
|
25
|
+
|
|
26
|
+
- title:
|
|
27
|
+
label: Title
|
|
28
|
+
required: false
|
|
29
|
+
- firstName:
|
|
30
|
+
label: First Name
|
|
31
|
+
- lastName:
|
|
32
|
+
label: Last Name
|
|
33
|
+
- position:
|
|
34
|
+
|
|
35
|
+
- fieldSet: access
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
id: product
|
|
2
|
+
label: Product
|
|
3
|
+
inTree: false
|
|
4
|
+
inVault: true
|
|
5
|
+
hasCanvas: false
|
|
6
|
+
|
|
7
|
+
layout:
|
|
8
|
+
columns: "3fr 1fr"
|
|
9
|
+
areas:
|
|
10
|
+
- ["main", "sidebar"]
|
|
11
|
+
|
|
12
|
+
regions:
|
|
13
|
+
main:
|
|
14
|
+
label: Product Content
|
|
15
|
+
sidebar:
|
|
16
|
+
label: Sidebar
|
|
17
|
+
|
|
18
|
+
allowedElements:
|
|
19
|
+
- text-block
|
|
20
|
+
- image_card
|
|
21
|
+
|
|
22
|
+
tabs:
|
|
23
|
+
settings:
|
|
24
|
+
label: "Product"
|
|
25
|
+
fields:
|
|
26
|
+
- fieldSet: page-base
|
|
27
|
+
- title:
|
|
28
|
+
label: Product Name
|
|
29
|
+
required: true
|
|
30
|
+
public: true
|
|
31
|
+
- slug:
|
|
32
|
+
linkedTo: "title"
|
|
33
|
+
- price:
|
|
34
|
+
label: Price (€)
|
|
35
|
+
type: number
|
|
36
|
+
public: true
|
|
37
|
+
- description:
|
|
38
|
+
label: Short Abstract
|
|
39
|
+
type: textarea
|
|
40
|
+
public: true
|
|
41
|
+
- fieldSet: meta
|
|
42
|
+
- fieldSet: access
|
|
43
|
+
|
|
44
|
+
media:
|
|
45
|
+
label: "Media"
|
|
46
|
+
fields:
|
|
47
|
+
# 🎯 ZONE 1: The Main Image (Strict crops for lists/catalogs)
|
|
48
|
+
- featuredImage:
|
|
49
|
+
label: Main Product Image
|
|
50
|
+
description: "This is the primary image used in product grids, search results, and catalogs."
|
|
51
|
+
type: asset
|
|
52
|
+
multiple: false
|
|
53
|
+
maxSizeMB: 15
|
|
54
|
+
allowedTypes: ["image/jpeg", "image/png", "image/webp"]
|
|
55
|
+
crops:
|
|
56
|
+
list_thumb:
|
|
57
|
+
label: "List View (4:3)"
|
|
58
|
+
aspectRatio: 1.333
|
|
59
|
+
catalog_card:
|
|
60
|
+
label: "Portrait Card (3:4)"
|
|
61
|
+
aspectRatio: 0.75
|
|
62
|
+
public: true
|
|
63
|
+
|
|
64
|
+
# 🎯 ZONE 2: The Gallery (Different crops for the carousel)
|
|
65
|
+
- gallery:
|
|
66
|
+
label: Product Gallery
|
|
67
|
+
description: "Drag up to 10 images here for the product detail carousel."
|
|
68
|
+
type: asset
|
|
69
|
+
multiple: true
|
|
70
|
+
maxItems: 10
|
|
71
|
+
allowedTypes: ["image/jpeg", "image/png", "image/webp"]
|
|
72
|
+
crops:
|
|
73
|
+
carousel:
|
|
74
|
+
label: "Carousel Hero (16:9)"
|
|
75
|
+
aspectRatio: 1.777
|
|
76
|
+
zoom:
|
|
77
|
+
label: "Detail Zoom (Square)"
|
|
78
|
+
aspectRatio: 1.0
|
|
79
|
+
public: true
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: navigation
|
|
2
|
+
label: "Site Navigation"
|
|
3
|
+
|
|
4
|
+
tabs:
|
|
5
|
+
settings:
|
|
6
|
+
label: "Tree"
|
|
7
|
+
fields:
|
|
8
|
+
- fieldSet: tree-base
|
|
9
|
+
- baseUrl:
|
|
10
|
+
label: Base URL
|
|
11
|
+
type: text
|
|
12
|
+
dbType: text
|
|
13
|
+
public: true
|
|
14
|
+
- defaultLanguage:
|
|
15
|
+
label: Channel Language / Locale
|
|
16
|
+
type: language-select
|
|
17
|
+
dbType: text
|
|
18
|
+
public: true
|
|
19
|
+
- maxDepth:
|
|
20
|
+
type: select
|
|
21
|
+
label: "Maximum Menu Depth"
|
|
22
|
+
default: "3"
|
|
23
|
+
options:
|
|
24
|
+
- "1"
|
|
25
|
+
- "2"
|
|
26
|
+
- "3"
|
|
27
|
+
- "4"
|
|
28
|
+
|
|
29
|
+
- fieldSet: access
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
id: _page
|
|
2
|
+
label: Page Old
|
|
3
|
+
inTree: true
|
|
4
|
+
inVault: true
|
|
5
|
+
hasCanvas: true
|
|
6
|
+
|
|
7
|
+
layout:
|
|
8
|
+
columns: "10fr 4fr"
|
|
9
|
+
areas:
|
|
10
|
+
- ["header", "header"]
|
|
11
|
+
- ["main", "sidebar"]
|
|
12
|
+
- ["footer", "footer"]
|
|
13
|
+
|
|
14
|
+
regions:
|
|
15
|
+
header:
|
|
16
|
+
label: Header
|
|
17
|
+
inherit: parent
|
|
18
|
+
main:
|
|
19
|
+
label: Content
|
|
20
|
+
sidebar:
|
|
21
|
+
label: Sidebar
|
|
22
|
+
footer:
|
|
23
|
+
label: Footer
|
|
24
|
+
inherit: parent
|
|
25
|
+
|
|
26
|
+
allowedElements:
|
|
27
|
+
- header
|
|
28
|
+
- hero
|
|
29
|
+
- text
|
|
30
|
+
- image_card
|
|
31
|
+
|
|
32
|
+
# 👉 TABS DEFINITION
|
|
33
|
+
tabs:
|
|
34
|
+
settings:
|
|
35
|
+
label: "Page"
|
|
36
|
+
fields:
|
|
37
|
+
# Imports core fields: title, slug, isHidden
|
|
38
|
+
- fieldSet: page-base
|
|
39
|
+
|
|
40
|
+
# Overrides & custom properties
|
|
41
|
+
- menuTitle:
|
|
42
|
+
label: Menu Title
|
|
43
|
+
type: text
|
|
44
|
+
dbType: text
|
|
45
|
+
public: true
|
|
46
|
+
placeholder: "Short title for navigation menus"
|
|
47
|
+
|
|
48
|
+
# SEO / OpenGraph metadata
|
|
49
|
+
- fieldSet: meta
|
|
50
|
+
|
|
51
|
+
# Role permissions & access control
|
|
52
|
+
- fieldSet: access
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
2
|
+
import Link from "@tiptap/extension-link";
|
|
3
|
+
import type { RteProfile } from "../../utils/rteProfiles";
|
|
4
|
+
|
|
5
|
+
export const profile: RteProfile = {
|
|
6
|
+
extensions: [StarterKit, Link.configure({ openOnClick: false })],
|
|
7
|
+
toolbar: [
|
|
8
|
+
"heading-1",
|
|
9
|
+
"heading-2",
|
|
10
|
+
"bold",
|
|
11
|
+
"italic",
|
|
12
|
+
"bullet-list",
|
|
13
|
+
"ordered-list",
|
|
14
|
+
"blockquote",
|
|
15
|
+
"link",
|
|
16
|
+
],
|
|
17
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// definitions/editor/header.ts
|
|
2
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
3
|
+
import Document from "@tiptap/extension-document";
|
|
4
|
+
import Subscript from "@tiptap/extension-subscript";
|
|
5
|
+
import Superscript from "@tiptap/extension-superscript";
|
|
6
|
+
import type { RteProfile } from "../../src/utils/rteProfiles";
|
|
7
|
+
|
|
8
|
+
// Custom document node forcing default top-level block to be a heading (H2)
|
|
9
|
+
const CustomDocument = Document.extend({
|
|
10
|
+
content: "heading block*",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const profile: RteProfile = {
|
|
14
|
+
extensions: [
|
|
15
|
+
CustomDocument,
|
|
16
|
+
StarterKit.configure({
|
|
17
|
+
document: false, // Replaces TipTap's default Document with CustomDocument
|
|
18
|
+
heading: { levels: [1, 2, 3, 4] },
|
|
19
|
+
}),
|
|
20
|
+
Subscript.configure(),
|
|
21
|
+
Superscript.configure(),
|
|
22
|
+
],
|
|
23
|
+
toolbar: [
|
|
24
|
+
"heading-1",
|
|
25
|
+
"heading-2",
|
|
26
|
+
"heading-3",
|
|
27
|
+
"heading-4",
|
|
28
|
+
"bold",
|
|
29
|
+
"italic",
|
|
30
|
+
"superscript",
|
|
31
|
+
"subscript",
|
|
32
|
+
],
|
|
33
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
2
|
+
import Link from "@tiptap/extension-link";
|
|
3
|
+
import type { RteProfile } from "../../utils/rteProfiles";
|
|
4
|
+
|
|
5
|
+
export const profile: RteProfile = {
|
|
6
|
+
extensions: [StarterKit, Link.configure({ openOnClick: false })],
|
|
7
|
+
toolbar: [
|
|
8
|
+
"bold",
|
|
9
|
+
"italic",
|
|
10
|
+
"bullet-list",
|
|
11
|
+
"ordered-list",
|
|
12
|
+
],
|
|
13
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// definitions/validators/iban.ts
|
|
2
|
+
|
|
3
|
+
export const iban = (value: any, ruleValue: any, field: any) => {
|
|
4
|
+
if (!value || !ruleValue) return "";
|
|
5
|
+
|
|
6
|
+
const isValid = /^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/.test(String(value).toUpperCase());
|
|
7
|
+
if (!isValid) {
|
|
8
|
+
return field.rules?.customMessage || "Invalid IBAN format.";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return "";
|
|
12
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightsideoy/kama",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
+
"defaults",
|
|
20
|
+
"definitions",
|
|
19
21
|
"bin",
|
|
20
22
|
"scripts",
|
|
21
23
|
"schema.sql"
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
// scripts/bundle-definitions.js
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import YAML from 'yaml';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
// 🎯 Package root is one directory up from scripts/
|
|
11
|
+
const packageRootDir = path.resolve(__dirname, '..');
|
|
12
|
+
|
|
13
|
+
// Look for definitions across package core AND consumer project overrides
|
|
7
14
|
function getDefinitionFiles(subDir) {
|
|
8
15
|
const fileMap = new Map();
|
|
16
|
+
|
|
9
17
|
const possibleDirs = [
|
|
18
|
+
// 1. Core package defaults (from inside node_modules or package source)
|
|
19
|
+
path.resolve(packageRootDir, "defaults/definitions", subDir),
|
|
20
|
+
path.resolve(packageRootDir, "definitions", subDir),
|
|
21
|
+
|
|
22
|
+
// 2. Fallbacks relative to node_modules if running from workspace root
|
|
23
|
+
path.resolve(process.cwd(), "node_modules/@brightsideoy/kama/defaults/definitions", subDir),
|
|
24
|
+
path.resolve(process.cwd(), "node_modules/@brightsideoy/kama/definitions", subDir),
|
|
25
|
+
|
|
26
|
+
// 3. Consumer project local overrides (highest priority — overwrites defaults)
|
|
10
27
|
path.resolve(process.cwd(), "defaults/definitions", subDir),
|
|
11
28
|
path.resolve(process.cwd(), "definitions", subDir),
|
|
12
29
|
path.resolve(process.cwd(), "schemas", subDir),
|
|
@@ -29,6 +46,7 @@ function getDefinitionFiles(subDir) {
|
|
|
29
46
|
entry.name.endsWith(".yml") ||
|
|
30
47
|
entry.name.endsWith(".json")
|
|
31
48
|
) {
|
|
49
|
+
// Overwrite earlier entries so local consumer files override package defaults
|
|
32
50
|
fileMap.set(entryRelPath, fullPath);
|
|
33
51
|
}
|
|
34
52
|
}
|
|
@@ -103,23 +121,31 @@ const outputContent = `// Auto-generated pre-bundled definitions for Kama Core E
|
|
|
103
121
|
export const BUNDLED_DEFINITIONS = ${JSON.stringify(bundled, null, 2)};
|
|
104
122
|
`;
|
|
105
123
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
// 🎯 Write to BOTH package dist/server locations so imports resolve cleanly
|
|
125
|
+
const targetDirs = [
|
|
126
|
+
path.resolve(packageRootDir, 'server/db'),
|
|
127
|
+
path.resolve(process.cwd(), 'node_modules/@brightsideoy/kama/server/db'),
|
|
128
|
+
path.resolve(process.cwd(), 'node_modules/@brightsideoy/kama/dist'),
|
|
129
|
+
path.resolve(process.cwd(), 'server/db'),
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
for (const dir of targetDirs) {
|
|
133
|
+
if (fs.existsSync(dir)) {
|
|
134
|
+
const outputPath = path.resolve(dir, 'bundled-definitions.ts');
|
|
135
|
+
fs.writeFileSync(outputPath, outputContent, 'utf-8');
|
|
136
|
+
// Also write .js version for built packages
|
|
137
|
+
const jsOutputPath = path.resolve(dir, 'bundled-definitions.js');
|
|
138
|
+
fs.writeFileSync(jsOutputPath, `export const BUNDLED_DEFINITIONS = ${JSON.stringify(bundled, null, 2)};\n`, 'utf-8');
|
|
139
|
+
}
|
|
109
140
|
}
|
|
110
141
|
|
|
111
|
-
|
|
112
|
-
fs.writeFileSync(outputPath, outputContent, 'utf-8');
|
|
113
|
-
|
|
114
|
-
console.log(`✅ Definitions bundled successfully into Kama Core:
|
|
142
|
+
console.log(`✅ Definitions bundled successfully:
|
|
115
143
|
• Nodes: ${Object.keys(bundled.rawNodes).length} (${Object.keys(bundled.rawNodes).join(', ')})
|
|
116
|
-
• Blocks: ${Object.keys(bundled.rawBlocks).length}
|
|
117
|
-
• Channels: ${Object.keys(bundled.rawChannels).length}
|
|
118
|
-
|
|
144
|
+
• Blocks: ${Object.keys(bundled.rawBlocks).length} (${Object.keys(bundled.rawBlocks).join(', ')})
|
|
145
|
+
• Channels: ${Object.keys(bundled.rawChannels).length} (${Object.keys(bundled.rawChannels).join(', ')})
|
|
146
|
+
• Trees: ${Object.keys(bundled.rawTrees).length} (${Object.keys(bundled.rawTrees).join(', ')})`);
|
|
119
147
|
|
|
120
|
-
//
|
|
121
|
-
// AUTO-GENERATE SQL INDEXES FROM SCHEMA
|
|
122
|
-
// ==========================================
|
|
148
|
+
// Auto-generate SQL Indexes
|
|
123
149
|
const indexQueries = new Set([
|
|
124
150
|
"-- Native Columns",
|
|
125
151
|
"CREATE INDEX IF NOT EXISTS idx_content_nodes_slug ON content_nodes (slug);",
|
|
@@ -130,7 +156,6 @@ const indexQueries = new Set([
|
|
|
130
156
|
|
|
131
157
|
function extractIndexes(obj) {
|
|
132
158
|
if (typeof obj !== 'object' || obj === null) return;
|
|
133
|
-
|
|
134
159
|
for (const [key, value] of Object.entries(obj)) {
|
|
135
160
|
if (typeof value === 'object' && value !== null) {
|
|
136
161
|
if (value.index === true && key !== "id" && key !== "slug" && key !== "contentType") {
|
|
@@ -148,5 +173,4 @@ const schemaSqlPath = path.resolve(process.cwd(), 'schema.sql');
|
|
|
148
173
|
|
|
149
174
|
if (fs.existsSync(schemaSqlPath)) {
|
|
150
175
|
fs.appendFileSync(schemaSqlPath, '\n\n' + sqlContent + '\n', 'utf-8');
|
|
151
|
-
console.log(`✅ Appended JSON auto-indexes directly to schema.sql`);
|
|
152
176
|
}
|