Initial commit

This commit is contained in:
2025-10-02 08:54:03 +02:00
commit ea54638227
1642 changed files with 53677 additions and 0 deletions

2
api/assets/dist.yml Normal file
View File

@@ -0,0 +1,2 @@
name: dist
path: ../frontend/dist

2
api/assets/fonts.yml Normal file
View File

@@ -0,0 +1,2 @@
name: fonts
path: ../frontend/assets/fonts

2
api/assets/logo.yml Normal file
View File

@@ -0,0 +1,2 @@
name: logo
path: ../frontend/logo

2
api/assets/variables.yml Normal file
View File

@@ -0,0 +1,2 @@
name: variables
path: ../frontend/assets/variables

View File

@@ -0,0 +1,253 @@
name: selfImprovementChallenge
meta:
allowExportAll: true
label:
de: SelfImp. Challenge
en: SelfImp. Challenge
muiIcon: label
backup:
active: true
collectionName: backups
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: title
label:
de: Titel
en: Title
filter: true
- source: type
label:
de: Typ
en: Type
filter: true
- source: slug
label:
de: Slug
en: Slug
filter: true
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: activeAt
- source: type
- source: title
- source: images
- source: slug
- name: introduction
label:
de: Kurzbeschreibung
en: Short Description
subFields:
- source: introduction
- source: howItWorks
- source: blog
subNavigation:
- name: modalForeign
defaultSort:
field: name
order: ASC
views: *views
defaultCallback:
eval: |
(entry) => {
parent.selectEntry(entry)
}
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: slug
type: string
meta:
label:
de: Slug
en: Slug
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: activeAt
type: date
meta:
label:
de: Aktiv ab
en: Active at
widget: date
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: type
type: number
meta:
label:
de: Typ
en: Type
widget: select
choices:
- name: Krass Kraft
id: 1
- name: Crazy Calm
id: 2
- name: Crazy Crave Control
id: 3
- name: Krass Kreativ
id: 4
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: images
type: object
meta:
label:
de: Bilder
en: Images
subFields:
- name: preview
type: string
meta:
label:
de: Mobile
en: Mobile
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: detailed
type: string
meta:
label:
de: Desktop
en: Desktop
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: title
type: string
meta:
label:
de: Titel
en: Title
- name: introduction
type: string[]
meta:
label:
de: Kurzbeschreibung
en: Short Description
useDefaultArray: true
widget: richtext
- name: howItWorks
type: object
meta:
label:
de: Wie es funktioniert
en: How it works
subFields:
- name: invitation
type: string
meta:
label:
de: Einladung
en: Invitation
- !include fields/contentBlocks/stepNr.yml
- name: blog
type: object
meta:
label:
de: Blog
en: Blog
subFields:
- name: blogId
type: string
meta:
label:
de: Blog ID
en: Blog ID
widget: foreignKey
foreign:
collection: content
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: thumbnail
type: string
meta:
label:
de: Thumbnail
en: Thumbnail
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: sources
type: object[]
meta:
label:
de: Quellen
en: Sources
subFields:
- name: source
type: string
meta:
label:
de: Quelle
en: Source
- name: url
type: string
meta:
label:
de: URL
en: URL

View File

@@ -0,0 +1,360 @@
name: orderReturnRequest
meta:
allowExportAll: true
label:
de: Retourenanfrage
en: Order Return Request
muiIcon: label
backup:
active: true
collectionName: backups
defaultSort:
field: insertTime
order: DESC
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: status
- source: notes
- name: customerDetails
label:
de: Kunden Details
en: Customer Details
subFields:
- source: email
- source: bigCommerceId
- name: products
label:
de: Produkte
en: Products
subFields:
- source: products
- name: returnShppingLabels
label:
de: Retourenlabels
en: Return Shipping Labels
subFields:
- source: returnShppingLabels
views: &views
- type: table
columns:
- source: status
filter: true
- source: email
filter: true
- source: bigCommerceId
filter:
type: foreignKey
- source: insertTime
filter: true
subNavigation:
- name: modalForeign
defaultSort:
field: "path"
order: "ASC"
views: *views
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
- name: new
label:
de: Neu
en: New
muiIcon: new
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: pending
- name: inProgress
label:
de: In Bearbeitung
en: In Progress
muiIcon: inProgress
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: approved
- name: done
label:
de: Abgeschlossen
en: Done
muiIcon: done
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: refunded
- name: failed
label:
de: Fehlgeschlagen
en: Failed
muiIcon: error
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: failed
- name: rejected
label:
de: Abgelehnt
en: Rejected
muiIcon: error
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: rejected
permissions:
public:
methods:
get: true
post: true
put: false
delete: true
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
get:
read:
type: javascript
file: hooks/orderReturnRequest/get_read.js
post:
create:
type: javascript
file: hooks/orderReturnRequest/post_create.js
return:
type: javascript
file: hooks/orderReturnRequest/post_return.js
put:
update:
type: javascript
file: hooks/orderReturnRequest/put_update.js
delete:
delete:
type: javascript
file: hooks/orderReturnRequest/delete_delete.js
return:
type: javascript
file: hooks/orderReturnRequest/delete_return.js
fields:
- name: status
type: string
meta:
label:
de: Status
en: Status
widget: select
choices:
- name: pending
id: pending
- name: approved
id: approved
- name: rejected
id: rejected
- name: refunded
id: refunded
- name: failed
id: failed
- name: email
type: string
meta:
label:
de: E-Mail
en: E-Mail
- name: bigCommerceId
type: number
meta:
label:
de: Bestellnummer
en: Order ID
widget: foreignKey
filter:
type: foreignKey
foreign:
collection: bigCommerceOrder
id: bigCommerceId
subNavigation: 0
render:
defaultCollectionViews: true
- name: returnShppingLabels
type: object[]
meta:
label:
de: Retourenlabels
en: Return Shipping Labels
subFields:
- name: cost
type: number
meta:
label:
de: Kosten
en: Cost
- name: label
type: file
meta:
label:
de: Label
en: Label
widget: file
- name: products
type: object[]
meta:
widget: containerLessObjectArray
label:
de: Produkte
en: Products
subFields:
- name: baseProductId
type: number
meta:
label:
de: Produkt ID
en: Product ID
widget: foreignKey
foreign:
collection: bigCommerceProduct
id: bigCommerceId
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: attachedImages
type: string[]
meta:
label:
de: Angehängte Bilder
en: Attached Images
widget: foreignKey
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
filter:
type: foreignKey
- name: quantity
type: number
meta:
label:
de: Menge
en: Quantity
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: productId
type: number
meta:
label:
de: Produkt ID in Bestellung
en: Product ID in Order
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: returnReason
type: string
meta:
label:
de: Retourengrund
en: Return Reason
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
widget: select
choices:
- name: falsche Größe
id: wrongSize
- name: falsche Farbe
id: wrongColor
- name: falsches Produkt
id: wrongProduct
- name: beschädigt
id: damaged
- name: zu Groß
id: tooLarge
- name: zu Klein
id: tooSmall
- name: nicht Wie Beschrieben
id: notAsDescribed
- name: schlechte Qualität
id: poorQuality
- name: sieht Anders Aus
id: looksDifferent
- name: nicht Mehr Benötigt
id: noLongerNeeded
- name: schlechtes Preis Leistungs Verhältnis
id: poorValue
- name: andere
id: other
- name: notes
type: string
meta:
label:
de: Notizen
en: Notes
widget: textarea
containerProps:
layout:
size:
default: "col-12"
small: "col-12"
large: "col-12"

View File

@@ -0,0 +1,183 @@
name: orderRevokeRequest
meta:
allowExportAll: true
label:
de: Bestellung Abbruch
en: Revoke Order
muiIcon: label
backup:
active: true
collectionName: backups
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: status
filter: true
- source: email
filter: true
- source: bigCommerceId
filter:
type: foreignKey
- source: insertTime
filter: true
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: email
- source: bigCommerceId
- source: printfulId
- name: editable
label:
de: Bearbeitbar
en: Editable
subFields:
- source: status
- source: notes
subNavigation:
- name: modalForeign
defaultSort:
field: "path"
order: "ASC"
views: *views
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
- name: new
label:
de: Neu
en: New
muiIcon: new
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: pending
- name: inProgress
label:
de: In Bearbeitung
en: In Progress
muiIcon: inProgress
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: refunded
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
get:
read:
type: javascript
file: hooks/orderRevokeRequest/get_read.js
post:
create:
type: javascript
file: hooks/orderRevokeRequest/post_create.js
return:
type: javascript
file: hooks/orderRevokeRequest/post_return.js
fields:
- name: status
type: string
meta:
label:
de: Status
en: Status
widget: select
choices:
- name:
de: Wartend
en: pending
id: pending
- name:
de: Zurückgezahlt
en: Refunded
id: refunded
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: email
type: string
meta:
label:
de: E-Mail
en: E-Mail
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: printfulId
type: number
meta:
label:
de: Printful Bestellungs-ID
en: Printful Order-ID
- name: bigCommerceId
type: number
meta:
label:
de: Bestellnummer
en: Order ID
widget: foreignKey
filter:
type: foreignKey
foreign:
collection: bigCommerceOrder
id: bigCommerceId
subNavigation: 0
render:
defaultCollectionViews: true
- name: notes
type: string
meta:
label:
de: Notizen
en: Notes
widget: string
inputProps:
multiline: true
containerProps:
layout:
size:
default: "col-12"
small: "col-12"
large: "col-12"

View File

@@ -0,0 +1,68 @@
name: qrCode
meta:
allowExportAll: true
label:
de: QR Codes
en: QR Codes
muiIcon: label
defaultSort:
field: name
order: ASC
backup:
active: true
collectionName: backups
views: &views
- type: table
columns:
- source: customer
filter:
type: foreignKey
- source: createdAt
filter: true
- source: id
renderValue:
raw: true
eval: |
(function(){
const id = $.id;
return `<button style="display: flex; align-items: center; padding: 8px 16px; background-color: #1D4ED8; color: white; font-weight: 600; border-radius: 6px; box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1); border: none; cursor: pointer; transition: background-color 0.3s ease;" onclick="event.stopPropagation(); event.preventDefault();navigator.clipboard.writeText('https://binkrassdufass.de/redirecttoprofile/${id}'); window.open('https://binkrassdufass.de/redirecttoprofile/${id}', '_blank')">Go to Profile <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-copy" style="margin-left: 8px;" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z"/></svg></button>` })()
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: customer
type: string
index: [single]
meta:
label:
de: Kunde
en: Customer
widget: foreignKey
foreign:
collection: bigCommerceCustomer
id: id
subNavigation: 0
render:
defaultCollectionViews: true
filter:
type: foreignKey
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,51 @@
name: action
# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
meta:
openapi:
disabled: true
# Navigationseintrag in der Admin-UI
label: { de: "Action", en: "Action" }
# Icon (Material UI) für den Navigationseintrag
muiIcon: web
views:
# Mobile Darstellung
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: id
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- id
permissions:
# öffentlicher Zugriff
public:
methods:
# Liste und Einzeleinträge lesen
# checked via hook
get: false
# neuen Eintrag anlegen
post: true
# Eintrag editieren
put: false
# Eintrag löschen
delete: false
# zum Projekt zugeordneter Benutzer ohne Zusatzberechtigungen
user:
methods:
get: false
post: false
put: false
delete: false
hooks:
post:
create:
type: javascript
file: hooks/action/post_create.js
# Feldliste der Kollektion
fields: []

131
api/collections/backups.yml Normal file
View File

@@ -0,0 +1,131 @@
name: backups
meta:
isBackupcollection: true
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: false
put: false
delete: false
# token als Zusatzsicherung gegen Spam, mehr siehe Hook
"token:${PUBLIC_TOKEN}":
methods:
get: false
post: true
put: false
delete: false
hooks:
post:
create:
type: javascript
file: hooks/backups/post_create.js
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
fields:
- name: collectionName
type: string
meta:
label:
de: Collection Name
en: Collection Name
- name: entryId
type: string
meta:
label:
de: Entry ID
en: Entry ID
- name: versionNr
type: number
meta:
label:
de: Version Nr
en: Version Nr
- name: manipulatedBy
type: string
meta:
label:
de: Manipulated By
en: Manipulated By
- name: eventDescription
type: string
meta:
label: Event Description
widget: select
choices:
- id: create
name:
de: Erstellt
en: Create
- id: update
name:
de: Update
en: Update
- id: delete
name:
de: Gelöscht
en: Delete
- id: recreate
name:
de: Wiederhergestellt
en: Recreate
- id: activate
name:
de: Aktiviert
en: Activate
- name: updateLogs
type: object[]
meta:
label:
de: Veränderungen
en: Update Logs
subFields:
- name: field
type: string
meta:
label:
de: Feldname
en: Fieldname
- name: previous
type: string
meta:
label:
de: Vorheriger Wert
en: Previous Value
- name: current
type: string
meta:
label:
de: Aktueller Wert
en: Current Value
- name: entry
type: object
meta:
label:
de: Eintrag
en: Entry

View File

@@ -0,0 +1,42 @@
name: bannerSlide
meta:
allowExportAll: true
label:
de: Banner
en: Banner
muiIcon: label
backup:
active: true
collectionName: backups
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: text
filter: true
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: text
type: string
meta:
label:
de: Inhalt
en: Content

View File

@@ -0,0 +1,278 @@
name: bigCommerceCustomer
# This is just so its easier to reference BigCommerce customer,
# its not intended to be used as a actual reference,
# just so its easier to reference customer in TibiCMS
meta:
label:
de: Kunde
en: Customer
views:
- type: table
columns:
- source: email
filter: true
- source: username
filter: true
- source: bigCommerceId
filter: true
- source: personalRecords.recording
filter:
type: foreignKey
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: email
- source: username
- source: bigCommerceId
- name: socialMedia
label:
de: Soziale Medien
en: Social Media
subFields:
- source: socialMediaAccounts
- name: personalRecords
label:
de: Persönliche Daten
en: Personal Records
subFields:
- source: personalRecords
- name: admin
label:
de: Admin
en: Admin
subFields:
- source: currentToken
- source: locked
backup:
active: true
collectionName: backups
subNavigation:
- name: modal
views:
- type: table
columns:
- source: email
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert.
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
hooks:
put:
# check and return jwt
update:
type: javascript
file: hooks/customer/put_update.js
get:
read:
type: javascript
file: hooks/customer/get_read.js
permissions:
public:
methods:
get: true
post: false
put: true
delete: false
user:
methods:
get: true
post: false
put: false
delete: false
token:${BIGCOMMERCE_WEBHOOK_TOKEN}:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: bigCommerceId
type: number
meta:
label:
de: BigCommerce ID
en: BigCommerce ID
helperText:
de: Die ID des Kunden in BigCommerce
en: The ID of the customer in BigCommerce
- name: email
type: string
meta:
label:
de: Angehängte E-Mail
en: Attached Email
helperText:
de: Die E-Mail-Adresse des Kunden
en: The email address of the customer
- name: username
type: string
index: [single, unique]
meta:
label:
de: Benutzername
en: Username
helperText:
de: Der Benutzername des Kunden
en: The username of the customer
- name: locked
type: boolean
meta:
label:
de: Gesperrt
en: Locked
helperText:
de: Ob der Kunde gesperrt ist
en: Whether the customer is locked
- name: currentToken
type: string
meta:
label:
de: Aktueller Token
en: Current Token
inputProps:
disabled: true
helperText:
de: Der aktuelle Token des Kunden
en: The current token of the customer
- name: socialMediaAccounts
type: object
meta:
label:
de: Soziale Medien
en: Social Media
helperText:
de: Die sozialen Medien des Kunden
en: The social media of the customer
widget: containerLessObject
subFields:
- name: instagramLink
type: string
meta:
label:
de: Instagram Link
en: Instagram Link
helperText:
de: Der Instagram-Link des Kunden
en: The Instagram link of the customer
- name: facebookLink
type: string
meta:
label:
de: Facebook Link
en: Facebook Link
helperText:
de: Der Facebook-Link des Kunden
en: The Facebook link of the customer
- name: twitterLink
type: string
meta:
label:
de: Twitter Link
en: Twitter Link
helperText:
de: Der Twitter-Link des Kunden
en: The Twitter link of the customer
- name: tiktokLink
type: string
meta:
label:
de: TikTok Link
en: TikTok Link
helperText:
de: Der TikTok-Link des Kunden
en: The TikTok link of the customer
- name: youtubeLink
type: string
meta:
label:
de: YouTube Link
en: YouTube Link
helperText:
de: Der YouTube-Link des Kunden
en: The YouTube link of the customer
- name: personalRecords
type: object[]
meta:
label:
de: Persönliche Daten
en: Personal Records
helperText:
de: Die persönlichen Daten des Kunden
en: The personal records of the customer
subFields:
- name: title
type: string
meta:
label:
de: Titel
en: Title
- name: description
type: string
meta:
label:
de: Beschreibung
en: Description
- name: ageAtRecording
type: number
meta:
label:
de: Alter bei Aufnahme
en: Age at Recording
- name: priority
type: number
meta:
label:
de: Priorität
en: Priority
- name: recording
type: string
meta:
label:
de: Aufnahme
en: Recording
widget: foreignKey
filter:
type: foreignKey
foreign:
collection: medialib
subNavigation: 0
id: id
render:
defaultCollectionViews: true
- name: thumbnail
type: string
meta:
label:
de: Vorschaubild
en: Thumbnail
widget: foreignKey
foreign:
collection: medialib
subNavigation: 0
id: id
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,281 @@
name: bigCommerceOrder
# This is just so its easier to reference BigCommerce order,
# its not intended to be used as a actual reference,
# just so its easier to reference order in TibiCMS
meta:
label:
de: Bestellung
en: Order
views: !include fieldLists/orderViews.yml
backup:
active: true
collectionName: backups
subNavigation:
- name: modal
views: !include fieldLists/orderViews.yml
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert.
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: false
token:${BIGCOMMERCE_WEBHOOK_TOKEN}:
methods:
get: true
post: true
put: true
delete: true
hooks:
get:
read:
type: javascript
file: hooks/order/get_read.js
fields:
- name: status
type: string
meta:
label:
de: Status
en: Status
widget: select
choices:
- id: draft
name:
de: Entwurf
en: Draft
- id: pending
name:
de: Ausstehend
en: Pending
- id: failed
name:
de: Fehlgeschlagen
en: Failed
- id: completed
name:
de: Abgeschlossen
en: Completed
- id: cancelled
name:
de: Storniert
en: Cancelled
- id: inprocess
name:
de: In Bearbeitung
en: In Process
- id: onhold
name:
de: Zurückgehalten
en: On Hold
- id: partial
name:
de: Teilweise
en: Partial
- id: fulfilled
name:
de: Erfüllt
en: Fulfilled
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: statusSetAt
type: date
meta:
label:
de: Status gesetzt am
en: Status set at
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: bigCommerceId
type: number
meta:
label:
de: BigCommerce ID
en: BigCommerce ID
helperText:
de: Die ID der Bestellung in BigCommerce
en: The ID of the Order in BigCommerce
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: customerBigCommerceId
type: number
meta:
label:
de: Kunde BigCommerce ID
en: Customer BigCommerce ID
helperText:
de: Die ID des Kunden in BigCommerce
en: The ID of the customer in BigCommerce
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: customerTibiId
type: string
meta:
label:
de: Kunde
en: Customer
filter:
type: foreignKey
widget: foreignKey
foreign:
collection: bigCommerceCustomer
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: products
type: object[]
meta:
label:
de: Produkte
en: Producte
widget: containerLessObjectArray
subFields:
- name: bigCommerceId
type: number
meta:
label:
de: BigCommerce ID
en: BigCommerce ID
helperText:
de: Die ID des Produkts in BigCommerce
en: The ID of the product in BigCommerce
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: tibiId
type: string
meta:
label:
de: Tibi ID
en: Tibi ID
widget: foreignKey
filter:
type: foreignKey
foreign:
collection: bigCommerceProduct
id: id
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: quantity
type: number
meta:
label:
de: Menge
en: Quantity
- name: shipments
type: object[]
meta:
label:
de: Lieferungen
en: Shipments
subFields:
- name: trackingUrl
type: string
meta:
label:
de: Tracking URL
en: Tracking URL
helperText:
de: Die URL, um das Paket zu verfolgen
en: The URL to track the package
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: trackingNumber
type: string
meta:
label:
de: Tracking Nummer
en: Tracking Number
helperText:
de: Die Tracking Nummer des Pakets
en: The tracking number of the package
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: carrier
type: string
meta:
label:
de: Carrier
en: Carrier
helperText:
de: Der Carrier des Pakets
en: The carrier of the package
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: sentAt
type: date
meta:
label:
de: Versendet am
en: Sent at
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,273 @@
name: bigCommerceProduct
# This is just so its easier to reference BigCommerce products,
# its not intended to be used as a actual reference,
# just so its easier to reference products in TibiCMS
meta:
label:
de: Produkt
en: Product
views: &views
- type: cardList
mediaQuery: "(min-width: 1200px)"
selectionPriority: 1
fields:
- source: productName
filter: true
name:
de: Produktname
en: Product Name
- source: previewImage
filter: true
name:
de: Vorschaubild
en: Preview Image
- source: printfulProductId
filter: true
name:
de: Printful Produkt ID
en: Printful Product ID
- source: forcedWarning
filter: true
name:
de: Warnungsanzeige
en: Warning Display
- type: table
mediaQuery: "(min-width: 600px)"
columns:
- source: productName
- source: previewImage
- source: bigCommerceSKU
- source: printfulProductId
- source: forcedWarning
- type: simpleList
primaryText: previewImage
secondaryText: productName
tertiaryText: printfulProductId
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: productName
- source: previewImage
- source: bigCommerceSKU
- source: bigCommerceId
- name: edit
label:
de: Bearbeitbar
en: Editable
subFields:
- source: forcedWarning
- source: printfulProductId
- name: sizingChart
label:
de: Größentabelle
en: Sizing Chart
subFields:
- source: sizingChart
subNavigation:
- name: modal
views: *views
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert.
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: false
delete: false
token:${BIGCOMMERCE_WEBHOOK_TOKEN}:
methods:
get: true
post: true
put: true
delete: true
hooks:
put:
update:
type: javascript
file: hooks/product/put_update.js
post:
create:
type: javascript
file: hooks/product/post_create.js
get:
read:
type: javascript
file: hooks/product/get_read.js
return:
type: javascript
file: hooks/product/get_return.js
fields:
- name: bigCommerceSKU
type: string
meta:
label:
de: BigCommerce SKU
en: BigCommerce SKU
helperText:
de: Die SKU des Produkts in BigCommerce
en: The SKU of the product in BigCommerce
- name: bigCommerceId
type: number
meta:
label:
de: BigCommerce ID
en: BigCommerce ID
helperText:
de: Die ID des Produkts in BigCommerce
en: The ID of the product in BigCommerce
- name: printfulProductId
type: string
meta:
label:
de: Printful Produkt ID
en: Printful Product ID
helperText:
de: Die ID des Produkts in Printful
en: The ID of the product in Printful
- name: previewImage
type: string
meta:
label:
de: Vorschaubild
en: Preview Image
widget: imageURL
- name: productName
type: string
meta:
label:
de: Produktname
en: Product Name
- name: forcedWarning
type: string
meta:
label:
de: Warnungsanzeige
en: Warning Display
- name: sizingChart
type: object
meta:
label:
de: Größentabelle
en: Sizing Chart
subFields:
- name: imageURL
type: string
meta:
label:
de: Bild
en: Image
widget: imageURL
- name: imageDescription
type: string
meta:
label:
de: Bildbeschreibung
en: Image Description
widget: richtext
- name: generalDescription
type: string
meta:
label:
de: Allgemeine Beschreibung
en: General Description
widget: richtext
- name: availableSizes
type: string[]
meta:
label:
de: Verfügbare Größen
en: Available Sizes
widget: select
choices:
- name: XS
id: XS
- name: S
id: S
- name: M
id: M
- name: L
id: L
- name: XL
id: XL
- name: 2XL
id: 2XL
- name: 3XL
id: 3XL
- name: 4XL
id: 4XL
- name: 5XL
id: 5XL
- name: 6XL
id: 6XL
- name: columns
type: object[]
meta:
label:
de: Spalten
en: Columns
subFields:
- name: label
type: string
meta:
label:
de: Label ID
en: Label ID
widget: foreignKey
foreign:
collection: module
id: label
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: sizes
type: string[]
meta:
label:
de: Größen
en: Sizes
useDefaultArray: true
widget: string
helperText:
de: In CM, selbe reihenfolge wie in der availableSizes
en: In CM, same order as in availableSizes

186
api/collections/contact.yml Normal file
View File

@@ -0,0 +1,186 @@
name: contact
# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
meta:
openapi:
disabled: true
# Navigationseintrag in der Admin-UI
label:
de: Kontaktanfragen
en: Contact request
# Icon (Material UI) für den Navigationseintrag
muiIcon: web
defaultSort:
field: insertTime
order: DESC
backup:
active: true
collectionName: backups
views: &views # Mobile Darstellung
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: status
secondaryText: request.email
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- source: status
label:
de: Status
en: Status
filter: true
- source: request.email
label:
de: E-Mail
en: E-Mail
filter: true
- source: request.name
label:
de: Name
en: Name
filter: true
- source: request.description
label:
de: Beschreibung
en: Description
filter: true
- source: insertTime
label:
de: Erstellt am
en: Created at
filter: true
subNavigation:
- name: modalForeign
defaultSort:
field: "path"
order: "ASC"
views: *views
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
- name: new
label:
de: Neu
en: New
muiIcon: new
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: new
- name: inProgress
label:
de: In Bearbeitung
en: In Progress
muiIcon: inProgress
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: inProgress
- name: done
label:
de: Abgeschlossen
en: Done
muiIcon: done
defaultSort:
field: insertTime
order: DESC
views: *views
filter:
status: done
hooks:
post:
create:
type: javascript
file: hooks/contact/post_create.js
return:
type: javascript
file: hooks/contact/post_return.js
permissions:
public:
methods:
get: false
post: true
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
# Feldliste der Kollektion
fields:
- name: status
type: string
meta:
label:
de: Status
en: Status
widget: select
choices:
- name: neue
id: new
- name: in Bearbeitung
id: inProgress
- name: abgeschlossen
id: done
- name: request
type: object
meta:
label:
de: Anfrage
en: Request
subFields:
- name: email
type: string
meta:
label:
de: E-Mail
en: E-Mail
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: name
type: string
meta:
label:
de: Name
en: Name
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: description
type: string
meta:
label:
de: Beschreibung
en: Description
inputProps:
multiline: true
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

321
api/collections/content.yml Normal file
View File

@@ -0,0 +1,321 @@
name: content
meta:
label: Inhalt
muiIcon: tableOfContents
allowExportAll: true
backup:
active: true
collectionName: backups
defaultSort:
field: insertTime
order: DESC
views:
- type: simpleList
selectionPriority: 0
primaryText: name
secondaryText: path
mediaQuery: "(min-width: 0px)"
tertiaryText: type
- type: table
selectionPriority: 1
mediaQuery: "(min-width: 700px)"
columns:
- source: active
name: Aktiv
filter: true
- source: type
name: Typ
filter: true
- source: name
name: Name
filter: true
- source: path
name: Pfad
filter: true
tablist:
activeTab: general
tabs:
- name: general
label:
de: Allgemein
en: General
subFields:
- source: active
- source: type
- source: name
- source: question
- source: path
- source: alternativePaths
- source: products
- name: block
label:
de: Inhalt
en: Content
subFields:
- source: blocks
- name: meta
label:
de: Meta
en: Meta
subFields:
- source: meta
subNavigation:
- name: modalForeign
defaultSort:
field: name
order: ASC
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
setDefault:
field: type
value: block
defaultCallback:
eval: |
(entry) => {
parent.selectEntry(entry)
}
- name: page
label:
de: Seiten
en: pages
muiIcon: book-open-page-variant
defaultSort:
field: insertTime
order: DESC
setDefault:
field: type
value: page
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
- source: path
name: Pfad
filter: true
filter:
type: page
- name: block
label:
de: Blöcke
en: blocks
muiIcon: view-grid
defaultSort:
# field: "sort"
# order: "MANUALLY"
field: insertTime
order: DESC
setDefault:
field: type
value: block
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
filter:
type: block
- name: helpcenterQuestion
label:
de: HC Fragen
en: HC Questions
muiIcon: book-open-page-variant
defaultSort:
field: insertTime
order: DESC
setDefault:
field: type
value: page
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
- source: path
name: Pfad
filter: true
filter:
type: helpcenterQuestion
- name: Blog
label:
de: Blog
en: Blog
muiIcon: book-open-page-variant
defaultSort:
field: insertTime
order: DESC
setDefault:
field: type
value: page
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
- source: path
name: Pfad
filter: true
filter:
type: blog
- name: product
label:
de: Produkte
en: Products
muiIcon: book-open-page-variant
defaultSort:
field: insertTime
order: DESC
setDefault:
field: type
value: product
views:
- type: table
columns:
- source: active
name: Aktiv
filter: true
- source: name
name: Name
filter: true
- source: path
name: Pfad
filter: true
filter:
type: product
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
projections:
navigation:
select:
path: 1
fields:
- !include fields/active.yml
- !include fields/contentType.yml
- name: products
type: number[]
meta:
label:
de: Produkte
en: Products
widget: foreignKey
dependsOn:
eval: $.type == "product"
foreign:
collection: bigCommerceProduct
id: bigCommerceId
subNavigation: 0
render:
defaultCollectionViews: true
- name: name
type: string
meta:
label:
de: Name
en: Name
helperText:
de: "Der Name wird nur intern verwendet."
en: "The name is only used internally."
containerProps:
layout:
breakAfter: true
size:
default: "col-6"
small: "col-12"
large: "col-6"
- type: string
name: question
index: [single]
meta:
label:
de: Frage
en: Question
dependsOn:
eval: $.type == "helpcenterQuestion"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- type: string
name: path
index: [single]
meta:
label:
de: Pfad
en: Path
helperText:
de: "Ein Pfad sollte mit einem / starten und ohne enden."
en: "A path should start with a / and end without one."
dependsOn:
eval: $.type == "page" || $.type == "helpcenterQuestion"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- !include fields/contentBlocks.yml
- !include fields/contentMeta.yml
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,38 @@
# just here since bgicommerces graphql api regarding cart and checkout isnt working (only cart create is possible, otherwise it always says cart is not existant)
########################################################################
# cart
########################################################################
name: dummyCartEndpoint
meta:
hideInNavigation: true
openapi:
disabled: true
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: false
post: false
put: false
delete: false
hooks:
get:
read:
type: javascript
file: hooks/cart/get_read.js
post:
validate:
type: javascript
file: hooks/cart/post_validate.js
fields:

View File

@@ -0,0 +1,74 @@
- name: products
type: object[]
meta:
label:
de: Produkte
en: Products
subFields:
- name: productImage
type: string
meta:
label:
de: Produktbild
en: Product Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: productReference
type: string
meta:
label:
de: Produktreferenz
en: Product Reference
widget: foreignKey
foreign:
collection: bigCommerceProduct
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: imageWidth
type: number
meta:
label:
de: Bildbreite
en: Image Width
helperText:
de: "Höhe des Bildes in Prozent."
en: "Height of the image in percent."
- name: imageHeight
type: number
meta:
label:
de: Bildhöhe
en: Image Height
helperText:
de: "Höhe des Bildes in Prozent."
en: "Height of the image in percent."
- name: imageTop
type: number
meta:
label:
de: Bildabstand oben
en: Image Top
helperText:
de: "Abstand des Bildes zum oberen Rand in Prozent."
en: "Distance of the image to the top edge in percent."
- name: imageLeft
type: number
meta:
label:
de: Bildabstand links
en: Image Left
helperText:
de: "Abstand des Bildes zum linken Rand in Prozent."
en: "Distance of the image to the left edge in percent."

View File

@@ -0,0 +1,33 @@
name: checkboxGroupInput
type: object
meta:
label:
de: Checkbox Gruppe
en: Checkbox Group
dependsOn:
eval: $parent?.inputWidgets?.includes('checkboxGroup')
helperText:
de: Ansammlung von Checkboxen
en: Collection of checkboxes
subFields:
- name: groupTitle
type: string
meta:
label:
de: Gruppe Titel
en: Group title
- name: checkboxes
type: object[]
meta:
label:
de: Checkbox Gruppe
en: Checkbox Group
direction: row
widget: containerLessObjectArray
subFields:
- name: standardInputProperties
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@@ -0,0 +1,17 @@
name: dateInput
type: object
meta:
label:
de: Normaler Kalender
en: Normal calendar
helperText:
de: Datumsfeld
en: Date field
dependsOn:
eval: $parent?.inputWidgets?.includes('defaultCalendar')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@@ -0,0 +1,46 @@
name: datePickerInput
type: object
meta:
label:
de: Custom Kalender
en: Custom Calendar
dependsOn:
eval: $parent?.inputWidgets?.includes('customCalendar')
subFields:
- name: props
type: object
meta:
label:
de: Datumauswahl Eigenschaften
en: Date selection properties
subFields:
- name: allowedDateRanges
type: object[]
meta:
label:
de: Erlaubte Datumsbereiche
en: Allowed date ranges
widget: containerLessObjectArray
subFields:
- !include ../../fields/from.yml
- name: to
type: date
meta:
label:
de: Bis
en: To
widget: date
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- !include ../../fields/excludedDays.yml
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@@ -0,0 +1,192 @@
- name: emailSubject
type: string
meta:
label:
de: Email Betreff
en: Email Subject
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailReciever
type: string
meta:
label:
de: Email Empfänger
en: Email Reciever
helperText:
de: "Bsp: xyz@gmail.com"
en: "E.g.: xyz@gmail.com"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- !include ../../fields/emailCC.yml
- name: emailIntroduction
type: string
meta:
label:
de: Email Einleitungssatz
en: Email Introduction Sentence
helperText:
de: "Bsp: Hallo xyz, sie haben eine neue Kaufanfrage erhalten!"
en: "E.g.: Hello xyz, you have received a new purchase request!"
- name: sendFormBtnText
type: string
meta:
label:
de: Formular Absenden Button Text
en: Form Submit Button Text
helperText:
de: "Bsp: Absenden"
en: "E.g.: Submit"
- name: rows
type: object[]
meta:
label:
de: Zeile
en: Row
widget: grid
addElementLabel: Zeile Hinzufügen
subFields:
- name: title
type: string
meta:
label:
de: Zeilenname
en: Row name
helperText:
de: "Sollte der Titel keinen Wert enthalten, wird kein Zeilenname angezeigt!"
en: "If the title does not contain a value, no row name will be displayed!"
- name: emailTitle
type: string
meta:
label:
de: Email Abschnitt Titel
en: Email section title
helperText:
de: "Sollte der Titel keinen Wert enthalten, wird kein Abschnitt Titel angezeigt!"
en: "If the title does not contain a value, no section title will be displayed!"
- name: columns
type: object[]
meta:
label:
de: Spalte
en: Column
addElementLabel:
de: Spalte hinzufügen
en: Add column
widget: grid
direction: horizontal
subFields:
- name: title
type: string
meta:
label:
de: Überschrift
en: Headline
helperText:
de: Optional
en: Optional
- name: emailTitle
type: string
meta:
label:
de: Email Abschnitt Titel
en: Email section title
- name: annotation
type: string
meta:
label:
de: Zusatzinformation
en: Additional information
- name: inputWidgets
type: string[]
meta:
label:
de: Angezeigte Eingabefelder
en: Displayed input fields
widget: selectArray
choices:
- name:
de: Nummernblock
en: Number block
id: labelNumber
- name:
de: Zeitenauswahlfeld
en: Time selection field
id: times
- name:
de: Auswahlfeld
en: Selection field
id: select
- name:
de: Datumsauswahl - Standard Kalender
en: Date selection - Standard calendar
id: defaultCalendar
- name:
de: Datumauswahl - Custom Kalender
en: Date selection - Custom calendar
id: customCalendar
- name:
de: Nummerfeld
en: Number field
id: number
- name:
de: Checkbox Gruppe
en: Checkbox group
id: checkboxGroup
- name:
de: Mehrfachauswahl
en: Multiple selection
id: multiSelect
- name:
de: Textfeld
en: Text field
id: text
- name:
de: Zeitenauswahl
en: Time selection
id: timeSelect
- name:
de: Standardauswahl
en: Standard selection
id: standardSelect
- !include standardSelect.yml
- !include labelNumberInput.yml
- !include timesInput.yml
- !include dateInput.yml
- !include numberInput.yml
- !include checkboxGroup.yml
- !include datePicker.yml
- !include multiSelectInput.yml
- !include textInputs.yml
- !include timeSelect.yml

View File

@@ -0,0 +1,79 @@
name: labelNumberInput
type: object[]
meta:
label:
de: Nummer block
en: Number block
dependsOn:
eval: $parent?.inputWidgets?.includes('labelNumber')
helperText:
de: Links beschreibender Text, rechts zahleneingabe
en: Left descriptive text, right number input
subFields:
- name: group
type: number
meta:
label:
de: Gruppe
en: Group
helpterText:
de: Pflichtfeld seperierung. Aus einem Nummernblock muss mindestens eine Gruppe input haben.
en: Mandatory field separation. A number block must have at least one group input.
- name: title
type: string
meta:
label: Titel
helperText:
de: Block Titel
en: Block title
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailName
type: string
meta:
label:
de: Email Name
en: Email name
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: block
type: object[]
meta:
label: Block
widget: containerLessObjectArray
subFields:
- name: label
type: string
meta:
label: Label
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: emailName
type: string
meta:
label:
de: Email Name
en: Email name
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,50 @@
name: multiSelectInput
type: object
meta:
label:
de: Mehrfachauswahl Input
en: Multi Select Input
dependsOn:
eval: $parent?.inputWidgets?.includes('multiSelect')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: options
type: object[]
meta:
label:
de: Mehrfachauswahl Optionen
en: Multi Select Options
direction: row
widget: containerLessObjectArray
subFields:
- name: name
type: string
meta:
label:
de: Name
en: Name
- name: props
type: object
meta:
label:
de: Mehrfachauswahl Eigenschaften
en: Multi Select Properties
subFields:
- name: additionalAddableValues
type: boolean
meta:
label:
de: Zusätzliche hinzufügbare Werte
en: Additional addable values
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,14 @@
name: numberInput
type: object
meta:
label:
de: Nummereingabe
en: Number Input
dependsOn:
eval: $parent?.inputWidgets?.includes('number')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@@ -0,0 +1,71 @@
- name: emailTitle
type: string
meta:
label:
de: Email Titel
en: Email title
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: placeholder
type: string
meta:
label:
de: Platzhalter
en: Placeholder
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: notRequired
type: boolean
meta:
label:
de: nicht Notwendig
en: not required
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: fieldOrder
type: number
meta:
label:
de: Reihenfolge
en: Order
helperText:
de: Die kleinste angegebene Zahl wird am weitesten oben in der Formularspalte stehen
en: The smallest specified number will be at the top of the form column.
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: textTitle
type: string
meta:
label:
de: Text Titel
en: Text title
helperText:
de: Alternative zu textPlaceholder, steht dann über dem Inputfeld
en: Alternative to textPlaceholder, then stands above the input field
- name: groupTitle
type: string
meta:
label:
de: Gruppe Titel
en: Group title

View File

@@ -0,0 +1,58 @@
name: standardSelect
type: object
meta:
label: Standardauswahl
dependsOn:
eval: $parent?.inputWidgets?.includes('standardSelect')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: selectEntries
type: object[]
meta:
label:
de: Auswahleingabe Möglichkeiten
en: Selection input options
widget: containerLessObjectArray
addElementLabel: Auswahleingabe hinzufügen
direction: horizontal
subFields:
- name: shownValue
type: string
meta:
label:
de: Angezeigter Wert
en: Displayed value
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: value
type: string
meta:
label:
de: per Email gesendeter Wert
en: Value sent by email
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: defaultValue
type: boolean
meta:
label:
de: Standardwert
en: Default value
helperText:
de: "Wird dieser Wert ausgewählt, wird er als Standardwert gesetzt"
en: "If this value is selected, it will be set as the default value"

View File

@@ -0,0 +1,52 @@
name: textInput
type: object[]
meta:
label: Textfeld
addElementLabel: Textfeld hinzufügen
dependsOn:
eval: $parent?.inputWidgets?.includes('text')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: textArea
type: boolean
meta:
label:
de: Großes Textfeld
en: Large text field
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"
- name: emailValidation
type: boolean
meta:
label:
de: E-Mail-Validierung
en: E-mail validation
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"
- name: telValidation
type: boolean
meta:
label:
de: Telefon-Validierung
en: Phone validation
containerProps:
layout:
size:
default: "col-4"
small: "col-6"
large: "col-4"

View File

@@ -0,0 +1,45 @@
name: timeSelect
type: object
meta:
label: Zeitenwahl
dependsOn:
eval: $parent?.inputWidgets?.includes('timeSelect')
subFields:
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml
- name: selectEntries
type: object[]
meta:
label: Auswahleingabe
widget: containerLessObjectArray
helperText: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
direction: horizontal
subFields:
- name: leftSide
type: string
meta:
label: Anfangspunkt
helperText: Bspw. 14:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: rightSide
type: string
meta:
label: Endpunkt
helperText: Bspw. 15:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,60 @@
name: timesInput
type: object
meta:
label:
de: Zeitenauswahlfeld
en: Time input
dependsOn:
eval: $parent?.inputWidgets?.includes('times')
helperText:
de: Selectfeld mit von - bis Angabe
en: Select field with from - to specification
subFields:
- name: times
type: object[]
meta:
label:
de: Zeitenauswahl Möglichkeiten
en: Time selection options
helperText:
de: "Die Angaben werden in folgendes Übersetzt: Anfangspunkt - Endpunkt"
en: "The information is translated into the following: starting point - end point"
direction: horizontal
widget: containerLessObjectArray
subFields:
- name: from
type: string
meta:
label:
de: Anfangspunkt
en: Starting point
helperText:
de: Bspw. 14:30
en: E.g. 14:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: to
type: string
meta:
label: Endpunkt
helperText:
de: Bspw. 15:30
en: E.g. 15:30
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: standardInputProperties
type: object
meta:
widget: containerLessObject
subFields: !include standardInputProperties.yml

View File

@@ -0,0 +1,35 @@
- name: title
type: string
meta:
label:
de: Titel
en: Title
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: description
type: string
meta:
label:
de: Beschreibung
en: Description
inputProps:
multiline: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: keywords
type: string
meta:
inputProps:
multiline: true
label:
de: Schlüsselwörter
en: Keywords

View File

@@ -0,0 +1,12 @@
- type: table
columns:
- source: status
filter: true
- source: customerTibiId
filter:
type: foreignKey
- source: insertTime
filter: true
- source: products.tibiId
filter:
type: foreignKey

View File

@@ -0,0 +1,16 @@
type: boolean
name: active
meta:
label:
de: Aktiv
en: Active
helperText:
de: Ist dies Aktiviert, so wird der Inhalt verfügbar.
en: If this is activated, the content will be available.
defaultValue: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,3 @@
backup:
active: true # sollen backups beim verändern erstellt werden
collectionName: backups # in welcher collection es gespeichert werden soll

View File

@@ -0,0 +1,72 @@
name: callToActionButtons
type: object[]
meta:
label:
de: Call to Action
en: Call to Action
subFields:
- name: buttonText
type: string
meta:
label:
de: Button-Text
en: Button Text
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: page
type: string
meta:
label:
de: Button-Link (URL)
en: Button link (URL)
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: ctaType
type: number
meta:
label: Button Farbe
widget: select
choices:
- id: 0
name: Primär
- id: 1
name: Sekundär
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: buttonTarget
type: string
meta:
label:
de: Button-Link (Ziel)
en: Button link (Target)
widget: select
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
choices:
- name:
de: im gleichen Fenster
en: in the same window
id: _self
- name:
de: in einem neuen Fenster
en: in a new window
id: _blank

View File

@@ -0,0 +1,465 @@
x-block-full-preview: &block-full-preview
eval: |
//js
(async () => {
const {ContentBlock, getRenderedElement} = await import($projectBase + "_/assets/dist/admin.mjs?t=" + $project?.updateTime)
const container = getRenderedElement(ContentBlock, {
props: {
block: Object.assign({}, $this, {
}),
apiBase: $projectBase,
},
addCss: [
$projectBase + "_/assets/dist/index.css",
$projectBase + "_/assets/dist/admin.css",
],
})
let style = "max-width: 1900px; background-color: white;"
// if (!$this?.aktiv) {
// style += "opacity: 0.5;"
// }
container.style = style
return container
})()
//!js
x-block-light-preview: &block-light-preview
eval: |
//js
"<div style=\"padding-left: 30px;\"><b>" +
($this.headline || "") + "</b>" +
($this.type ?
" &nbsp; &nbsp; <small>Blocktyp: " +
{
"columns": "Spalten",
"predefinedBlock": "Vordefinierter Block",
}[$this.type] +
"</small>" :
"") +
($this.anchorId ?
" &nbsp; &nbsp; <small>#" + $this.anchorId +
"</small>" :
"") +
"<br>" +
($this.subline || "") +
"</div>"
//!js
raw: true
name: blocks
type: object[]
meta:
label:
de: Inhalt
en: Content
#widget: containerLessObjectArray
widget: previewBasedObjectArray
pathStep:
title: Inhalt
preview: *block-full-preview
folding:
previewFolded: *block-full-preview
previewUnfolded: *block-light-preview
metaElements:
tablist:
tabs:
- name: allgemein
label: Allgemein
subFields:
- source: topline
- source: headline
- source: headlineH1
- source: doublyLined
- source: subline
- source: anchorId
- source: headlineLink
- source: headlineLinkText
- name: callToAction
label: Call to Action
subFields:
- source: callToActionButtons
- name: paddingBackground
label: Hintergrund und Abstand
subFields:
- source: background
- source: padding
- source: contentWidth
- source: crinkledSection
- source: additionalHeightBottom
subFields:
########################### globale Einstellungen ###########################
- name: headline
type: string
meta:
label:
de: Überschrift
en: Headline
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: headlineH1
type: boolean
meta:
label:
de: Überschrift als H1
en: Headline as H1
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: headlineLink
type: string
meta:
label:
de: Überschrift-Link
en: Headline-Link
foreign:
collection: content
id: path
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: headlineLinkText
type: string
meta:
label:
de: Überschrift-Link
en: Headline-Link
foreign:
collection: content
id: path
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- !include ./callToActionButton.yml
- name: doublyLined
type: boolean
meta:
label:
de: Doppelt unterstrichen
en: Doubly underlined
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: subline
type: string
meta:
label:
de: Unterzeile
en: Subline
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: topline
type: string
meta:
label:
de: Topline
en: Topline
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: anchorId
type: string
meta:
# dependsOn:
# eval: |
# (function() {
# return $parent?.type !== 'predefinedBlock'
# })()
label:
de: Anker-ID
en: Anchor ID
helperText:
de: Der Block kann über diese Anker-Id direkt über links mit URL#Anker-ID angesprungen werden.
en: The block can be jumped directly via links with URL#AnchorID.
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: crinkledSection
type: boolean
meta:
label:
de: Geknitterter Abschnitt
en: crinkled Section
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: background
type: object
meta:
label:
de: Hintergrund
en: Background
subFields:
- name: color
type: string
meta:
label:
de: Hintergrundfarbe
en: Background color
widget: select
choices:
- name:
de: weiß / transparent
en: white / transparent
id: white
- name:
de: schwarz
en: black
id: black
defaultValue: white
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: image
type: string
meta:
label:
de: Hintergrundbild
en: Background Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render: !include ../lib/foreignMediaRender.yml
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: minHeight
type: string
meta:
label:
de: Mindesthöhe
en: Min height
widget: select
choices:
- name:
de: keine
en: none
id: "none"
- name:
de: Normale höhe
en: Normal height
id: normal
- name:
de: erweiterte Höhe
en: extended height
id: extended
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: headerHeightUp
type: boolean
meta:
label:
de: Um höhe des Header nach oben
en: Header up
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: overlay
type: boolean
meta:
label:
de: Overlay
en: Overlay
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: noVerticalPadding
type: boolean
meta:
label:
de: Kein vertikaler Innenabstand
en: No vertical padding
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
helperText:
de: Nur nötig, wenn man nicht mit den "geknittertem Abschnitt" arbeitet
en: Only not necessary if you work with the "crinkled section"
- name: noHorizontalMargin
type: boolean
meta:
label:
de: Kein horizontaler Außenabstand
en: No horizontal margin
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: contentWidth
type: number
meta:
widget: select
label:
de: Breite
en: Width
choices:
- id: 0
name:
de: 100%
en: 100%
- id: 1
name:
de: Schmal
en: Narrow
- id: 2
name:
de: normal
en: normal
- name: type
type: string
meta:
label:
de: Typ
en: Type
widget: select
containerProps:
layout:
breakBefore: true
breakAfter: true
size:
default: "col-6"
small: "col-12"
large: "col-6"
defaultValue: columns
choices:
- name:
de: keine Auswahl
en: no selection
id: ""
- name:
de: Text- und Bild-Spalten
en: Text and image columns
id: columns
- name:
de: Vordefinierter Block
en: Predefined Block
id: predefinedBlock
- name:
de: Produkt Slider
en: Product Slider
id: productSlider
- name:
de: Haupt Homepage
en: Main Homepage
id: homepage
- name:
de: Geteilte Homepage
en: Splitted Homepage
id: splittedHomepage
- name:
de: Verbessere Dich Spalte
en: Improve Yourself Column
id: improveYourselfDescription
- name:
de: Chapter Preview
en: Chapter Preview
id: selfImprovementChapterPreview
- name:
de: Bewertungsvorschau
en: Rating Preview
id: ratingPreview
- name: StepNr
id: stepNr
- name: additionalHeightBottom
type: boolean
meta:
label:
de: Zusätzliche Höhe unten
en: Additional height bottom
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
########################### Blöcke ############################
###############################################################
- !include ./contentBlocks/columns.yml
- !include ./contentBlocks/form.yml
- !include ./contentBlocks/predefined.yml
- !include ./contentBlocks/productSlider.yml
- !include ./contentBlocks/MainHomepage.yml
- !include ./contentBlocks/SplittedHompage.yml
- !include ./contentBlocks/ImproveYourselfDescription.yml
- !include ./contentBlocks/selfImprovementChapter.yml
- !include ./contentBlocks/ratingsPreview.yml
- !include ./contentBlocks/stepNr.yml

View File

@@ -0,0 +1,70 @@
name: cta
type: object
meta:
label: Call To Action Zeile
dependsOn:
eval: $parent.type == 'cta'
subFields:
- name: upperHeadline
type: string
meta:
label: Über Überschrift
containerProps:
layout:
size:
default: "col-6"
small: "col-6"
large: "col-6"
- name: description
type: string
meta:
label: Überschrift beschreibung
containerProps:
layout:
size:
default: "col-6"
small: "col-6"
large: "col-6"
- name: whiteHeadline
type: string
meta:
label: Weißer Teil Überschrift
containerProps:
layout:
size:
default: "col-6"
small: "col-6"
large: "col-6"
- name: redHeadline
type: string
meta:
label: Roter Teil Überschrift
containerProps:
layout:
size:
default: "col-6"
small: "col-6"
large: "col-6"
- name: headlineArrangement
type: string
meta:
label: Headline Anordnung
widget: select
containerProps:
layout:
size:
default: "col-12"
small: "col-12"
large: "col-12"
choices:
- id: row
name: in einer Zeile
- id: column
name: in einer Spalte
- !include ../callToActionButton.yml

View File

@@ -0,0 +1,54 @@
name: improveYourselfDescription
type: object
meta:
label:
de: Verbessere dich Beschreibung
en: Improve Yourself Description
dependsOn:
eval: $parent.type === 'improveYourselfDescription'
subFields:
- name: upperDescription
type: string
meta:
label:
de: Obere Beschreibung
en: Upper Description
widget: richtext
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: lowerDescription
type: string
meta:
label:
de: Untere Beschreibung
en: Lower Description
widget: richtext
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: image
type: string
meta:
label:
de: Bild
en: Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,28 @@
name: mainHomepage
type: object
meta:
label: Hauptseite
dependsOn:
eval: $parent.type == 'homepage'
subFields:
- name: type
type: string
meta:
label: Typ
widget: select
choices:
- id: cta
name: Call To Action
- !include CTACol.yml
- name: image
type: string
meta:
label: Bild
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,23 @@
name: splittedHomepage
type: object
meta:
label:
de: Geteilte Homepage
en: Splitted Homepage Block
dependsOn:
eval: $parent.type === 'splittedHomepage'
subFields:
- name: chapters
type: string[]
meta:
label:
de: Kapitel
en: Chapters
widget: foreignKey
foreign:
collection: selfImprovementChapter
id: id
sort: name
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,265 @@
x-column-preview: &column-preview
eval: |
//js
(async () => {
const {ColumnsColumn, getRenderedElement} = await import($projectBase + "_/assets/dist/admin.mjs?t=" + $project?.updateTime)
let c = ColumnsColumn
const container = getRenderedElement(c, {
props: {
column: Object.assign({}, $this, {
}),
apiBase: $projectBase,
},
addCss: [
$projectBase + "_/assets/dist/index.css",
$projectBase + "_/assets/dist/admin.css",
],
})
let style = "background-color: white;"
style += "width: 600px;"
// if (!$this?.aktiv) {
// style += "opacity: 0.5;"
// }
container.style = style
return container
})()
//!js
name: columns
type: object[]
meta:
label:
de: Spalten
en: columns
dependsOn:
eval: $parent.type == 'columns'
pathStep:
title: Spalten
direction: horizontal
widget: previewBasedObjectArray
preview: *column-preview
folding:
previewFolded: *column-preview
previewUnfolded:
eval: |
"<div style=\"padding-left: 30px;\">" + ($this.type == "image" ? "Bild" : "Text") + "-Spalte (Breite: " + ($this.colWidth ? $this.colWidth + "/12" : "automatisch" ) + ")</div>"
raw: true
defaultValue:
eval: |
[{type: "text", colWidth: 0}]
metaElements:
- type
- colWidth
- verticalAlign
subFields:
- name: type
type: string
meta:
label:
de: Typ
en: Type
widget: select
defaultValue: text
choices:
- name:
de: Text
en: Text
id: text
- name:
de: Bild
en: Image
id: image
- name:
de: CTA
en: CTA
id: cta
containerProps:
layout:
size:
default: "col-4"
small: "col-12"
large: "col-4"
- name: colWidth
type: number
meta:
widget: select
label:
de: Spaltenbreite
en: Column width
choices:
- id: -1
name:
de: automatische Breite
en: auto
- id: 6
name:
de: 1/2
en: 1/2
- id: 4
name:
de: 1/3
en: 1/3
defaultValue: -1
containerProps:
layout:
size:
default: "col-4"
small: "col-12"
large: "col-4"
- name: verticalAlign
type: string
meta:
widget: select
label:
de: vertikale Ausrichtung
en: vertical alignment
choices:
- id: top
name:
de: oben
en: top
- id: middle
name:
de: mittig
en: middle
- id: bottom
name:
de: unten
en: bottom
defaultValue: top
containerProps:
layout:
size:
default: "col-4"
small: "col-12"
large: "col-4"
- name: text
type: string
meta:
label:
de: Text
en: text
widget: richtext
dependsOn:
eval: $parent.type == 'text'
- name: images
type: string[]
meta:
label:
de: Bild
en: Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render: !include ../../lib/foreignMediaRender.yml
dependsOn:
eval: $parent.type == 'image'
- name: imageMobileBackground
type: boolean
meta:
label:
de: Bild auf Mobilgeräten in hintergrund
en: Image on mobile devices in background
dependsOn:
eval: $parent.type == 'image'
- name: forceFullHeight
type: boolean
meta:
label:
de: volle Bildhöhe erzwingen
en: full Force image height
dependsOn:
eval: $parent.type == 'image'
- name: imageHoverEffect
type: boolean
meta:
label:
de: Bild hover effekt
en: Image hover effect
dependsOn:
eval: $parent.type == 'image'
- name: links
type: object[]
meta:
label:
de: Links
en: Links
folding:
force: true
previewFolded:
eval: |
"<div style=\"padding-left: 30px;\">Link: <b>" + ($this.text || "") + "</b></div>"
raw: true
dependsOn:
eval: $parent.type == 'text'
subFields:
- name: text
type: string
meta:
label:
de: Text
en: Text
- name: url
type: string
meta:
label:
de: URL
en: URL
- name: target
type: string
meta:
label:
de: Ziel
en: Target
widget: select
choices:
- name:
de: im gleichen Fenster
en: in the same window
id: _self
- name:
de: in einem neuen Fenster
en: in a new window
id: _blank
- name: style
type: string
meta:
label:
de: Stil
en: Style
widget: select
defaultValue: primary
choices:
- name:
de: primär (roter Hintergrund)
en: primary (red background)
id: primary
- name:
de: sekundär (rote Schrift)
en: secondary (red text)
id: secondary
- id: tertiary
name:
de: normaler Link (graue Schrift)
en: normal link (grey text)
- name:
de: externer Link (Icon links)
en: external link (icon left)
id: external
- name:
de: Download Link (Icon links)
en: download link (icon left)
id: download
- !include ./CTACol.yml

View File

@@ -0,0 +1,7 @@
name: form
type: object
meta:
widget: containerLessObject
dependsOn:
eval: $parent.type == 'form'
subFields: !include ../../fieldLists/formular/form.yml

View File

@@ -0,0 +1,28 @@
name: predefinedBlock
type: object
meta:
label:
de: Vordefinierter Block
en: Predefined Block
dependsOn:
eval: |
(function() {
return $parent?.type === 'predefinedBlock'
})()
subFields:
- name: id
type: string
meta:
label:
de: Inhalt
en: Include
widget: foreignKey
foreign:
collection: content
id: id
subNavigation: 0
render:
eval: |
(function() {
return $foreignEntry?.name || $foreignEntry?.id
})()

View File

@@ -0,0 +1,85 @@
name: productSlider
type: object
meta:
label:
de: Produktslider
en: Product Slider
dependsOn:
eval: $parent.type === 'productSlider'
subFields:
- name: productSource
type: string
meta:
label:
de: Produktdatenquelle
en: Product Data Source
widget: select
choices:
- name:
de: Manuelle Auswahl
en: Manual Selection
id: manual
- name:
de: Kategorie Id
en: Category id
id: category
- name:
de: Bestseller
en: Bestseller
id: bestseller
- name:
de: Neue Produkte
en: New Products
id: newProducts
- name:
de: Hervorgehoben
en: Featured
id: featured
- name:
de: Angebote
en: Discounted
id: discounted
- name: productIds
type: number[]
meta:
label:
de: Produkt IDs
en: Product IDs
dependsOn:
eval: $parent.productSource === 'manual' || $parent.productSource === "discounted"
widget: foreignKey
foreign:
collection: bigCommerceProduct
id: bigCommerceId
subNavigation: 0
render:
defaultCollectionViews: true
- name: categoryId
type: string
meta:
label:
de: Kategorie
en: Category
dependsOn:
eval: $parent.productSource === 'category'
- !include ../callToActionButton.yml
- name: headline
type: string
meta:
label:
de: Überschrift
en: Headline
- name: topLine
type: string
meta:
label:
de: Top Line
en: Top Line

View File

@@ -0,0 +1,25 @@
name: ratingsPreview
type: object
meta:
label:
de: Bewertungsvorschau
en: Ratings Preview
dependsOn:
eval: $parent.type === 'ratingPreview'
subFields:
- name: ratings
type: object[]
meta:
widget: containerLessObjectArray
subFields:
- name: rating
type: string
meta:
label: rating
widget: foreignKey
foreign:
collection: rating
id: id
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,35 @@
name: selfImprovementChapterPreview
type: object[]
meta:
label:
de: Vorschau
en: Preview
dependsOn:
eval: $parent.type === 'selfImprovementChapterPreview'
subFields:
- name: chapter
type: string
meta:
label:
de: Kapitel
en: Chapter
widget: foreignKey
foreign:
collection: selfImprovementChapter
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: previewImage
type: string
meta:
label:
de: Vorschaubild
en: Preview Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,73 @@
name: steps
type: object
meta:
label:
de: Stepp Nr
en: Step Nr
dependsOn:
eval: $parent.type === 'stepNr' || !$parent.type
subFields:
- name: horizontal
type: boolean
meta:
label:
de: Horizontal
en: Horizontal
- name: color
type: string
meta:
label:
de: Farbe
en: Color
widget: select
choices:
- name: red
id: red
- name: items
type: object[]
meta:
label:
de: Items
en: Items
widget: containerLessObjectArray
subFields:
- name: nr
type: number
meta:
label:
de: Nr
en: Nr
- name: title
type: string
meta:
label:
de: Titel
en: Title
- name: descriptions
type: string[]
meta:
widget: string
useDefaultArray: true
label:
de: Beschreibung
en: Description
inputProps:
multiline: true
- name: image
type: string
meta:
label:
de: Bild
en: Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,103 @@
name: meta
type: object
meta:
label:
de: Meta Agaben
en: Meta Data
helperText:
de: Diese Angaben werden für die Suchmaschinenoptimierung verwendet.
en: These data are used for search engine optimization.
dependsOn:
eval: $?.type != "block"
subFields:
- name: title
type: string
meta:
label:
de: Titel
en: Title
helperText:
de: Alternativ wird der Name verwendet.
en: Alternatively the name is used.
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: description
type: string
meta:
label:
de: Beschreibung
en: Description
inputProps:
multiline: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: keywords
type: string
meta:
inputProps:
multiline: true
label:
de: Schlüsselwörter
en: Keywords
- name: isArticle
type: boolean
meta:
label:
de: Ist Artikel
en: Is Article
helperText:
de: "Wenn aktiviert, wird der Inhalt als Artikel behandelt."
en: "If activated, the content is treated as an article."
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: hasFAQ
type: boolean
meta:
label:
de: Hat FAQ
en: Has FAQ
helperText:
de: "Wenn aktiviert, wird der Inhalt als FAQ behandelt."
en: "If activated, the content is treated as a FAQ."
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: FAQ
type: object[]
meta:
label:
de: FAQ
en: FAQ
subFields:
- name: question
type: string
meta:
label:
de: Frage
en: Question
- name: answer
type: string
meta:
label:
de: Antwort
en: Answer
inputProps:
multiline: true

View File

@@ -0,0 +1,35 @@
type: string
name: type
meta:
label:
de: Inhaltstyp
en: Content Type
widget: select
defaultValue: page
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
choices:
- name:
de: Seite
en: Page
id: page
- name:
de: Block
en: Block
id: block
- name:
de: Helpcenter Frage
en: Helpcenter Question
id: helpcenterQuestion
- name: Blog
id: blog
- name: product
id: product

View File

@@ -0,0 +1,11 @@
name: emailCC
type: string[]
meta:
label:
de: Email CC
en: Email CC
widget: string
useDefaultArray: true
helperText:
de: "Bsp: zyx@gmail.com"
en: "E.g.: zyx@gmail.com"

View File

@@ -0,0 +1,40 @@
name: excludeDays
type: string[]
meta:
label: Auszuschließende Wochentage
widget: checkboxArray
choices:
- id: monday
name:
de: Montag
en: Monday
- id: tuesday
name:
de: Dienstag
en: Tuesday
- id: wednesday
name:
de: Mittwoch
en: Wednesday
- id: thursday
name:
de: Donnerstag
en: Thursday
- id: friday
name:
de: Freitag
en: Friday
- id: saturday
name:
de: Samstag
en: Saturday
- id: sunday
name:
de: Sonntag
en: Sunday

View File

@@ -0,0 +1,6 @@
name: file
type: file
meta:
label:
de: Datei
en: File

View File

@@ -0,0 +1,7 @@
type: object
name: formular
meta:
label:
de: Formular
en: Form
widget: jsonField

View File

@@ -0,0 +1,13 @@
name: from
type: date
meta:
label:
de: Von
en: From
widget: date
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

View File

@@ -0,0 +1,11 @@
name: sort
type: number
meta:
label:
de: Manuelle Sortierung
en: Manual Sorting
inputProps:
{ readonly: true, placeholder: { de: "Wert wird automatisch gesetzt", en: "Value is set automatically" } }
helperText:
de: Dieses Feld wird für die manuelle Sortierung benötigt. Sobald ein Eintrag per Drag&Drop verschoben wurde, wird die neue Position innerhalb der Liste eingetragen.
en: This field is required for manual sorting. As soon as an entry is moved using Drag&Drop, the new position is entered in the list.

View File

@@ -0,0 +1,41 @@
type: cardList
mediaQuery: "(min-width: 1200px)"
selectionPriority: 1
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file
pageAsDropArea: false
fields:
- source: file
name:
de: Datei
en: File
filter: true
- source: category
name:
de: Kategorie
en: Category
filter: true
- source: tags
name:
de: Tags
en: Tags
foreign: true
filter: true
- source: title
name:
de: Titel
en: Title
filter: true
- source: updateTime
type: datetime
label:
de: letztes Update
en: last update
filter: true

View File

@@ -0,0 +1,25 @@
type: simpleList
mediaQuery: "(min-width: 0px)"
defaultSelect: false
selectionPriority: 3 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file # gibt an, in welches feld die datei hochgeladen werden soll
pageAsDropArea: false # wenn true, wird filedrop area garnicht erst angezeigt, da die ganze seite drag n drop funktionalität hat
primaryText:
source: file
filter: true
secondaryText:
source: alt
filter: true
tertiaryText:
source: category
filter: true

View File

@@ -0,0 +1,41 @@
type: table
mediaQuery: "(min-width: 800px)"
defaultSelect: false
selectionPriority: 2
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file
pageAsDropArea: false
columns:
- source: file
name:
de: Datei
en: File
filter: true
- source: category
name:
de: Kategorie
en: Category
filter: true
- source: tags
name:
de: Tags
en: Tags
foreign: true
filter: true
- source: title
name:
de: Titel
en: Title
filter: true
- source: updateTime
type: datetime
label:
de: letztes Update
en: last update
filter: true

View File

@@ -0,0 +1,10 @@
multiupload:
fields:
- source: category # gibt an, welche Felder in der Modalansicht bearbeitet werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
prefilledFields: # gibt an, welche Felder in der Modalansicht vorbefüllt werden können, wenn die Eigenschaft nicht festgelegt ist, werden automatisch alle Felder ausgewählt
- source: title
defaultValue: # extrahiert den namen des files und fügt ihn in das feld "title" ein
eval: |
(function(){
return "Title" + $file.name
})()

View File

@@ -0,0 +1,17 @@
name: pageTitle
type: string
meta:
label:
de: Titel der Seite
en: Page Title
helperText:
de: "Dieser Titel wird in der Seite als h1 angezeigt."
en: "This title is displayed in the page as h1."
dependsOn:
eval: $.type == "page"
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,9 @@
name: text
type: string
meta:
widget: richtext
label:
de: Text
en: text
dependsOn:
eval: $parent.contentType == 'text'

38
api/collections/form.yml Normal file
View File

@@ -0,0 +1,38 @@
name: form
uploadPath: ../media/forms
meta:
label: Formular
muiIcon: web
backup:
active: true
collectionName: backups
views:
- type: table
columns:
- source: formular
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
post:
create:
type: javascript
file: hooks/forms/post_create.js
return:
type: javascript
file: hooks/forms/post_return.js
fields:
- !include fields/form.yml

View File

@@ -0,0 +1,143 @@
name: helpCenterChapter
# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
meta:
openapi:
disabled: true
# Navigationseintrag in der Admin-UI
label:
de: Helpcenter Kapitel
en: Helpcenter Chapter
backup:
active: true
collectionName: backups
# Icon (Material UI) für den Navigationseintrag
muiIcon: web
tablist:
activeTab: general
tabs:
- name: general
label:
de: Allgemein
en: General
subFields:
- source: title
- source: slug
- source: brightIcon
- source: darkIcon
- name: questions
label:
de: Fragen
en: Questions
subFields:
- source: questions
views:
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- source: title
name: Titel
filter: true
- source: slug
name: Slug
filter: true
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
# Feldliste der Kollektion
fields:
- name: title
type: string
meta:
label:
de: Titel
en: Title
- name: slug
type: string
meta:
label:
de: Slug
en: Slug
- name: brightIcon
type: string
meta:
label:
de: Icon Hell
en: Icon Bright
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: darkIcon
type: string
meta:
label:
de: Icon Dunkel
en: Icon Dark
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: questions
type: object[]
meta:
label:
de: Fragen
en: Questions
widget: containerLessObjectArray
subFields:
- name: priority
type: boolean
meta:
label:
de: Priorität
en: Priority
helperText:
de: ob sie direkt ganz oben angezeigt werden soll
en: if it should be displayed directly at the top
- name: page
type: string
meta:
label:
de: Seite
en: Page
widget: foreignKey
foreign:
collection: content
id: path
subNavigation: 0
render:
defaultCollectionViews: true

View File

@@ -0,0 +1,13 @@
raw: true
eval: |
//js
(function() {
let out = ""
if ($foreignEntry?.file?.src && $foreignEntry?.file?.type?.startsWith("image/")) {
out += "<img src='" + $projectBase + "medialib/" + $foreignEntry.id + "/" + $foreignEntry.file.src + "?filter=s' style='max-width: 100%;' /><br>"
}
out += $foreignEntry?.title || ""
return out
})()
//!js

View File

@@ -0,0 +1,55 @@
# Der Key des Objektes definiert den Namen des Filters.
# Jeder Filter ist eine Liste von Bildmanipulationen, die
# nacheinander angewandt werden.
# Die manipulierten Bilder werden gecachet. Ein nachträgliches
# Anpassen der Filter erfordert also das Löschen der gecachten
# Dateien welche sich jeweils neben den original Bilddateien
# im "uploadPath" der Kollektion befinden.
xs:
- fit: true
height: 90
width: 90
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true
s:
- fit: true
height: 300
width: 300
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true
m:
- fit: true
height: 600
width: 600
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true
l:
- fit: true
height: 1200
width: 1200
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true
xl:
- fit: true
height: 2000
width: 2000
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true
xxl:
- fit: true
height: 4000
width: 4000
resampling: lanczos
quality: 90
skipLargerDimension: true
skipLargerFilesize: true

View File

@@ -0,0 +1,38 @@
type: cardList
mediaQuery: "(min-width: 1200px)"
selectionPriority: 1
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file
pageAsDropArea: false
fields:
- source: title
name:
de: Titel
en: Title
filter: true
- source: file
name: Datei
- source: tags
name:
de: Tags
en: Tags
filter:
type: foreignKey
- source: updateTime
type: datetime
filter: false
label:
de: letztes Update
en: last update
- source: file.type
name:
de: Dateityp
en: Filetype
filter: true

View File

@@ -0,0 +1,26 @@
type: simpleList
mediaQuery: "(min-width: 0px)"
defaultSelect: false
selectionPriority: 3 #gibt an, wenn mediaQuery passt, mit welcher priorität es default mäßig ausgewählt sein soll, je niedriger, desto wichtiger
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file # gibt an, in welches feld die datei hochgeladen werden soll
pageAsDropArea: false # wenn true, wird filedrop area garnicht erst angezeigt, da die ganze seite drag n drop funktionalität hat
primaryText:
source: file
# filter: true
secondaryText:
source: title
filter: true
tertiaryText:
source: tags
filter:
type: foreignKey

View File

@@ -0,0 +1,35 @@
type: table
mediaQuery: "(min-width: 800px)"
defaultSelect: false
selectionPriority: 2
fileDropArea:
label:
{
de: "Ziehen Sie Dateien per Drag and Drop hierher oder klicken Sie, um Dateien auszuwählen.",
en: "Drag and drop some files here, or click to upload.",
}
helperText: { de: "Maximale Uploadgröße: 1,54 MB", en: "Maximum upload size: 1.54MB" }
targetField: file
pageAsDropArea: false
columns:
- source: file
name:
de: Datei
en: File
filter: true
- source: tags
name:
de: Tags
en: Tags
filter:
type: foreignKey
- source: file.type
label:
de: Dateityp
en: Filetype
filter: true
- source: updateTime
type: datetime
label:
de: letztes Update
en: last update

View File

@@ -0,0 +1,6 @@
quickEdit: # Erlaubt das Bearbeiten von Einträgen in der Listenansicht, ohne dass eine neue Seite geöffnet wird
enabled: true
fields: # felder, die in dieser Ansicht bearbeitet werden können
- title
- alt
- file

View File

@@ -0,0 +1,6 @@
name: fulltextindex # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$** # definiert einen Volltextindex über alle Felder. Der spezielle Operator $text wird verwendet, um einen Volltextindex zu erstellen, und der Operator $\*\* bezeichnet alle Felder in der Sammlung.
background: true
unique: false # Wenn auf true gesetzt, erzwingt dies, dass der Index eindeutige Werte enthält. Wenn Sie versuchen, einen Eintrag mit einem bereits indizierten Wert hinzuzufügen, wird ein Fehler ausgelöst.
defaultLanguage: german # Wird verwendet, um die Sprache für Textindizes festzulegen. Dies ist wichtig für die Volltextsuche, da verschiedene Sprachen unterschiedliche Tokenisierungs- und Stemmungsregeln haben.

View File

@@ -0,0 +1,153 @@
name: lighthouse
meta:
label: Lighthouse
hideInNavigation: true
muiIcon: web
views:
- type: table
mediaQuery: "(min-width: 600px)"
columns:
- source: insertTime
filter: true
- source: perfomance
filter: true
- source: accessibility
filter: true
- source: bestPractices
filter: true
- source: seo
filter: true
- type: simpleList
mediaQuery: "(max-width: 599px)"
primaryText: insertTime
secondaryText: performance
tertiaryText: accessibility
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
projections:
dashboard:
hooks:
post:
create:
type: javascript
file: hooks/lighthouse/post_create.js
indexes:
- !include lib/textIndex.yml
fields:
- name: analyzedPaths
type: string[]
meta:
label:
de: Analysierten Pfade
en: Analyzed Paths
- name: performance
type: number
meta:
label: Performance
- name: accessibility
type: number
meta:
label:
en: Accessibility
de: Zugänglichkeit
- name: bestPractices
type: number
meta:
label:
en: Best Practices
de: Beste Praktiken
- name: seo
type: number
meta:
label:
en: SEO
de: SEO
- name: lighthouseMetrics
type: object
meta:
label: Lighthouse Metrics
subFields:
- name: FCPS
type: number
meta:
label:
en: First Contentful Paint Score
de: Erster Inhaltlicher Anstrich Score
- name: FCPV
type: number
meta:
label:
en: First Contentful Paint Value
de: Erster Inhaltlicher Anstrich Wert
- name: FMPV
type: number
meta:
label:
de: Erster Bedeutungsvoller Anstrich Wert
en: First Meaningful Paint Value
- name: FMPS
type: number
meta:
label:
en: First Meaningful Paint Score
de: Erster Bedeutungsvoller Anstrich Score
- name: SIS
type: number
meta:
label:
en: Speed Index Score
de: Geschwindigkeitsindex Score
- name: SIV
type: number
meta:
label:
en: Speed Index Value
de: Geschwindigkeitsindex Wert
- name: TTIS
type: number
meta:
label:
en: Time to Interactive Score
de: Zeit bis zur Interaktion Score
- name: TTIV
type: number
meta:
label:
en: Time to Interactive Value
de: Zeit bis zur Interaktion Wert
- name: FPIDS
type: number
meta:
label:
de: Erste potenzielle Eingabe Verzögerung Score
en: First Potential Input Delay Score
- name: FPIDV
type: number
meta:
label:
en: First Potential Input Delay Value
de: Erste potenzielle Eingabe Verzögerung Wert

View File

@@ -0,0 +1,32 @@
name: lighthouseSubpath
meta:
label: Lighthouse Subpaths
hideInNavigation: true
muiIcon: web
views:
- type: table
columns:
- source: lighthouseSubpath
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- type: string
name: lighthouseSubpath
meta:
label:
de: Zu analysierenden Pfad
en: Path to analyze

61
api/collections/login.yml Normal file
View File

@@ -0,0 +1,61 @@
# no data in collection, only for post hook
name: login
uploadPath: ../media/login
# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
meta:
openapi:
disabled: true
hideInNavigation: true
# Navigationseintrag in der Admin-UI
label: { de: "Login", en: "Login" }
# Icon (Material UI) für den Navigationseintrag
muiIcon: web
# Identifizierung eines Eintrags für z.B. Select-Boxen in der Admin-UI
rowIdentTpl: { twig: "{{ id }}" }
# Standardsortierung der Liste
defaultSort: { field: "id", order: "ASC" }
# Admin-Backend Ansichten
defaultImageFilter: s
views:
# Mobile Darstellung
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: id
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- id
# Zugriff auf diese Kollektion
permissions:
# öffentlicher Zugriff
public:
methods:
# Liste und Einzeleinträge lesen
get: false
# neuen Eintrag anlegen
post: true
# Eintrag editieren
put: false
# Eintrag löschen
delete: false
# zum Projekt zugeordneter Benutzer ohne Zusatzberechtigungen
user:
methods:
get: true
post: true
put: true
delete: true
hooks:
post:
# check and return jwt
create:
type: javascript
file: hooks/login/post_create.js
# Feldliste der Kollektion
fields: []

View File

@@ -0,0 +1,24 @@
name: lookCombination
meta:
allowExportAll: true
label:
de: Styling Kombinationen
en: Look Combination
muiIcon: label
views: []
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields: []

View File

@@ -0,0 +1,210 @@
name: medialib
uploadPath: ../media/medialib
meta:
allowExportAll: true
label:
de: Medienbibliothek
en: Media Library
muiIcon: multimedia
defaultSort:
field: sort
order: MANUALLY
backup:
active: true
collectionName: backups
quickEdit:
enabled: true
fields:
- title
- alt
- file
- tags
defaultImageFilter: xs
multiupload:
fields:
- source: category
prefilledFields:
- source: title
defaultValue:
eval: |
(function(){
return $file.name.split(".")[0]
})()
- source: alt
defaultValue:
eval: |
(function(){
return $file.name.split(".")[0]
})()
views: &views
- !include fields/medialibSimpleList.yml
- !include fields/medialibTable.yml
- !include fields/medialibCardList.yml
subNavigation:
- name: modalForeign
defaultSort:
field: "path"
order: "ASC"
views: *views
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
- name: websiteContent
label: Inhalt
muiIcon: accountGroup
setDefault:
field: type
value: websiteContent
defaultSort:
field: "sort"
order: "MANUALLY"
views: *views
filter:
"type": "websiteContent"
- name: other
label: Andere
muiIcon: accountGroup
defaultSort:
field: "sort"
order: "MANUALLY"
views: *views
filter:
"type": { $ne: "websiteContent" }
permissions:
public:
methods:
get: true
post: true
put: false
delete: true
validProjections:
- list
- details
user:
methods:
get: true
post: true
put: true
delete: true
token:${TOKEN}:
methods:
get: true
post: true
put: true
delete: true
pages:
methods:
get: true
post: true
put: true
delete: true
projections:
dashboard:
select:
details:
select:
file: 0
list:
select:
file: 1
alt: 1
hooks:
put:
return:
type: javascript
file: hooks/clear_cache.js
delete:
delete:
type: javascript
file: hooks/medialib/delete_delete.js
imageFilter: !include lib/imageFilter.yml
fields:
- !include fields/file.yml
- name: type
type: string
meta:
label:
de: Typ
en: Type
widget: select
choices:
- name: websiteContent
id: websiteContent
- name: returnOrderFoto
id: returnOrderFoto
- name: alt
type: string
meta:
label:
de: Alternativtext
en: Alternative text
helperText:
de: Der Alternativtext wird angezeigt, wenn die Datei nicht geladen werden kann.
en: The alternative text is displayed if the file cannot be loaded.
- name: title
type: string
meta:
label:
de: Titel
en: Title
helperText:
de: Der Titel wird angezeigt, wenn die Datei geladen wird.
en: The title is displayed when the file is loaded.
- name: category
type: string
meta:
label:
de: Kategorie
en: Category
- name: tags
type: string[]
meta:
label:
de: Tags
en: Tags
widget: foreignKey
filter:
type: foreignKey
foreign:
collection: tag
id: id
sort: name
subNavigation: 0
render:
raw: true
eval: |
//js
$foreignEntry?.name
//!js
- name: comment
type: string
meta:
label:
de: Kommentar
en: Comment
inputProps:
multiline: true
- !include fields/manualSort.yml
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,93 @@
name: module
meta:
label: Module
allowExportAll: true
backup:
active: true
collectionName: backups
views:
- type: table
columns:
- source: type
name: Typ
filter: true
- source: label
name: Label
filter: true
- source: germanLabelTranslation
name: Deutsche Übersetzung
filter: true
subNavigation:
- name: modal
views:
- type: table
columns:
- source: type
defaultCallback:
eval: |
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: type
type: string
meta:
label:
de: Modultyp
en: Module Type
helperText:
de: "Wählen Sie den Typ des Moduls aus."
en: "Choose the type of the module."
widget: select
choices:
- name: Größen Label
id: sizeLabel
- name: label
type: string
index: [single, unique]
meta:
label:
de: Label
en: Label
- name: germanLabelTranslation
index: [single, unique]
type: string
meta:
label:
de: Deutsche Übersetzung
en: German Translation
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,179 @@
name: navigation
uploadPath: ../media/navigation
meta:
label: "Navigation"
muiIcon: navigation
views:
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: tree
- type: table
mediaQuery: "(min-width:600px)"
columns:
- source: tree
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: false
put: true
delete: false
x-folding: &folding
previewUnfolded:
eval: |
$this?.name + ' (Ziel: ' + ($this?.external ? $this?.externalUrl || '' : ($this?.page || '') + ($this?.hash ? '#' + $this.hash : '')) + ')' + ($this?.elements?.length ? ' <small>' + $this?.elements?.length + ' Sub-Navigationselement(e)</small>' : '')
raw: true
previewFolded:
eval: |
$this?.name + ' (Ziel: ' + ($this?.external ? $this?.externalUrl || '' : ($this?.page || '') + ($this?.hash ? '#' + $this.hash : '')) + ')' + ($this?.elements?.length ? ' <small>' + $this?.elements?.length + ' Sub-Navigationselement(e)</small>' : '')
raw: true
x-elemente: &elemente
name: elements
type: object[]
meta:
label:
de: Elemente
en: elements
folding: *folding
x-name: &name
name: name
type: string
meta:
label:
de: Name
en: name
helperText:
de: Dieser Name wird zur Anzeige in der Navigation verwendet.
en: This name is used for display in the navigation.
x-page: &page
name: page
type: string
meta:
label:
de: Seite pfad
en: page path
dependsOn:
eval: |
!$parent?.external
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
x-hash: &hash
name: hash
type: string
meta:
label:
de: Anker
en: anchor
dependsOn:
eval: |
!$parent?.external
helperText:
de: Geben Sie hier den Anker ein, zu dem der Link führen soll. (ohne '#' am Anfang)
en: Enter the anchor to which the link should lead. (without '#' at the beginning)
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
x-external: &external
name: external
type: boolean
meta:
label:
de: Externer Link
en: external link
helperText:
de: Wenn aktiviert, wird der Link in einem neuen Tab geöffnet.
en: If activated, the link will be opened in a new tab.
x-externalUrl: &externalUrl
name: externalUrl
type: string
meta:
label:
de: Externer Link
en: external link
dependsOn:
eval: |
$parent?.external
helperText:
de: Geben Sie hier die URL ein, zu der der Link führen soll.
en: Enter the URL to which the link should lead.
hooks:
post:
return:
type: javascript
file: hooks/clear_cache.js
put:
return:
type: javascript
file: hooks/clear_cache.js
delete:
return:
type: javascript
file: hooks/clear_cache.js
fields:
- name: tree
type: number
meta:
label: Baum
widget: select
helperText:
de: Die Servicenavigation sollte Seiten wie bspw. die Datneschutzerklärung oder das Impressum umfassen.
en: The service navigation should include pages such as the data protection declaration or the imprint.
defaultValue: 0
choices:
- id: 0
name:
de: Hauptnavigation
en: main navigation
- id: 1
name:
de: Service Navigation
en: Service Navigation
- id: 2
name:
de: Rechtliche Navigation
en: Legal Navigation
- <<: *elemente
subFields:
- *name
- *external
- *page
- *hash
- *externalUrl
- <<: *elemente
subFields:
- *name
- *external
- *page
- *hash
- *externalUrl
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,75 @@
name: productBackgroundImage
meta:
allowExportAll: true
label:
de: Produkt Bg.
en: Product Bg.
muiIcon: label
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: type
filter: true
- source: image
filter:
type: foreignKey
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: type
type: string
meta:
label:
de: Typ
en: Type
widget: select
choices:
- id: standard
label:
de: Standard
en: Standard
- id: dark
label:
de: Dunkel
en: Dark
- name: image
type: string
meta:
label:
de: Tibi ID
en: Tibi ID
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
filter:
type: foreignKey
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,54 @@
name: productBenefit
meta:
allowExportAll: true
label:
de: Product Vorteile
en: Product Benefits
muiIcon: label
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: title
label:
de: Titel
en: Title
- source: description
label:
de: Beschreibung
en: Description
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: title
type: string
meta:
label:
de: Titel
en: Title
- name: description
type: string
meta:
widget: richtext
label:
de: Beschreibung
en: Description

301
api/collections/rating.yml Normal file
View File

@@ -0,0 +1,301 @@
name: rating
meta:
label: { de: "Bewertungen", en: "Ratings" }
muiIcon: reviews
views: &views
- type: simpleList
mediaQuery: "max-width: 600px"
- type: table
columns:
- source: bigCommerceProductId
filter:
type: foreignKey
- source: bigcommerceOrderId
filter:
type: foreignKey
- source: rating.overall
filter: true
- source: status
filter: true
tablist:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: bigCommerceProductId
- source: bigcommerceOrderId
- source: status
- source: review_date
- source: bigcommerceReviewId
- name: rating
label:
de: Bewertung
en: Rating
subFields:
- source: rating
- source: comment
- source: title
subNavigation:
- name: modal
views: *views
defaultCallback: # Standard-Callback-Funktion, die ausgeführt wird, wenn keine andere spezifiziert ist.
eval: | # Der Code wird als JavaScript evaluiert.
//js
(entry) => { // Diese Funktion nimmt den Eintrag (entry) als Argument.
parent.selectEntry(entry) // Die Funktion selectEntry auf dem übergeordneten Objekt wird mit dem Eintrag als Argument aufgerufen.
}
//!js
permissions:
public:
methods:
get: true
post: true
put: true
delete: false
user:
methods:
get: true
post: true
put: true
delete: false
hooks:
delete:
delete:
type: javascript
file: hooks/rating/delete_delete.js
return:
type: javascript
file: hooks/rating/delete_return.js
get:
read:
type: javascript
file: hooks/rating/get_read.js
post:
validate:
type: javascript
file: hooks/rating/post_validate.js
create:
type: javascript
file: hooks/rating/post_create.js
return:
file: hooks/rating/post_return.js
type: javascript
put:
validate:
type: javascript
file: hooks/rating/put_validate.js
update:
type: javascript
file: hooks/rating/put_update.js
return:
file: hooks/rating/put_return.js
type: javascript
fields:
- name: bigcommerceOrderId
type: number
index: [single]
meta:
filter:
type: foreignKey
label: { de: "Interne Bestellnummer", en: "Internal Order Id" }
widget: foreignKey
foreign:
collection: bigCommerceOrder
subNavigation: 0
id: bigCommerceId
render:
defaultCollectionViews: true
validator:
required: true
- name: bigCommerceProductId
index: [single]
type: number
meta:
filter:
type: foreignKey
label: { de: "Produkt", en: "Product" }
widget: foreignKey
foreign:
collection: bigCommerceProduct
subNavigation: 0
id: bigCommerceId
render:
defaultCollectionViews: true
validator:
required: true
- name: rating
index: [single]
type: object
meta:
widget: containerLessObject
label: { de: "Bewertung", en: "Rating" }
subFields:
- name: quality
type: number
meta:
label: { de: "Qualität", en: "Quality" }
helperText: { de: "1 - Schlecht; 5 - Sehr Gut", en: "1 - Bad; 5 - Very Good" }
validator:
eval: |
(function () {
return $this >= 0 && $this <= 5;
})()
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: priceQualityRatio
type: number
meta:
label: { de: "Preis-Leistungs-Verhältnis", en: "Price-Quality Ratio" }
helperText: { de: "1 - Schlecht; 5 - Sehr Gut", en: "1 - Bad; 5 - Very Good" }
validator:
eval: |
(function () {
return $this >= 0 && $this <= 5;
})()
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: comfort
type: number
meta:
label: { de: "Komfort", en: "Comfort" }
helperText: { de: "1 - Unbequem; 5 - Sehr Bequem", en: "1 - Uncomfortable; 5 - Very Comfortable" }
validator:
eval: |
(function () {
return $this >= 0 && $this <= 5;
})()
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: overall
type: number
meta:
label: { de: "Gesamt", en: "Overall" }
helperText: { de: "1 - Schlecht; 5 - Sehr Gut", en: "1 - Bad; 5 - Very Good" }
validator:
eval: |
(function () {
return $this >= 0 && $this <= 5;
})()
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-4"
- name: comment
type: string
meta:
label: { de: "Kommentar", en: "Comment" }
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
inputProps:
multiline: true
- name: title
type: string
meta:
label: { de: "Titel", en: "title" }
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
inputProps:
multiline: true
- name: review_date
type: date
validator:
eval: |
(function () {
return (new Date($this) !== "Invalid Date") && !isNaN(new Date($this));
})()
meta:
label: { de: "Erstellungsdatum", en: "Creation date" }
defaultValue:
eval: new Date()
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: status
type: string
index: [single]
validator:
eval: (["pending", "approved", "rejected"].includes($this))
meta:
label: Status
widget: "select"
defaultValue: pending
choices:
- name: { de: wartend, en: pending }
id: pending
- name: { de: bestätigt, en: approved }
id: approved
- name: { de: abgelehnt, en: rejected }
id: rejected
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: bigcommerceReviewId
type: string
meta:
label:
de: "BigCommerce Review Id"
en: "BigCommerce Review Id"
helperText:
de: "Die ID der Bewertung in BigCommerce"
en: "The ID of the review in BigCommerce"
indexes:
- name: fulltext # Ein eindeutiger Name für den Index. Es ist optional, wird jedoch empfohlen, um den Index später leicht identifizieren zu können.
key: # Bestimmt, auf welche Felder der Index angewendet werden soll. Dies kann ein einfacher String sein, wenn der Index nur ein Feld umfasst, oder ein Array von Strings, wenn der Index mehrere Felder umfasst.
- $text:$**

View File

@@ -0,0 +1,196 @@
name: selfImprovementChapter
meta:
allowExportAll: true
label:
de: SelfImp. Kapitel
en: SelfImp. Chapter
muiIcon: label
backup:
active: true
collectionName: backups
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: title
label:
de: Titel
en: Title
filter: true
- source: shortDescription
label:
de: Kurzbeschreibung
en: Short Description
filter: true
tabs:
activeTab: generalDetails
tabs:
- name: generalDetails
label:
de: Allgemeine Details
en: General Details
subFields:
- source: title
- source: alias
- source: previewVideo
- source: previewImage
- source: locked
- name: homepage
label:
de: Homepage
en: Homepage
subFields:
- source: shortDescription
- source: description
subNavigation:
- name: modalForeign
defaultSort:
field: name
order: ASC
views: *views
defaultCallback:
eval: |
(entry) => {
parent.selectEntry(entry)
}
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: type
type: number
meta:
label:
de: Typ
en: Type
widget: select
choices:
- name: Krass Kraft
id: 1
- name: Crazy Calm
id: 2
- name: Crazy Crave Control
id: 3
- name: Krass Kreativ
id: 4
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: title
type: string
meta:
label:
de: Titel
en: Title
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: alias
type: string
meta:
label:
de: Alias
en: Alias
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: shortDescription
type: string
meta:
label:
de: Kurze Beschreibung
en: Short Description
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: description
type: string
meta:
widget: richtext
label:
de: Beschreibung
en: Description
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"
- name: previewVideo
type: string
meta:
label:
de: Vorschau Video
en: Preview Video
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: previewImage
type: string
meta:
label:
de: Vorschau Bild
en: Preview Image
widget: foreignKey
foreign:
collection: medialib
id: id
subNavigation: 0
render:
defaultCollectionViews: true
- name: locked
type: boolean
meta:
label:
de: Gesperrt
en: Locked
helperText:
de: Wenn gesperrt, kann das Kapitel nicht geöffnet werden.
en: If locked, the chapter cannot be opened.
containerProps:
layout:
size:
default: "col-6"
small: "col-12"
large: "col-6"

View File

@@ -0,0 +1,74 @@
name: shopStatus
# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
meta:
openapi:
disabled: true
# Navigationseintrag in der Admin-UI
backup:
active: true
collectionName: backups
label:
de: Shop Status
en: Shop Status
# Icon (Material UI) für den Navigationseintrag
muiIcon: web
views:
# Mobile Darstellung
- type: simpleList
mediaQuery: "(max-width:599px)"
primaryText: status
secondaryText: password
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- source: status
label:
de: Status
en: Status
filter: true
- source: password
label:
de: Passwort
en: Password
filter: true
permissions:
# öffentlicher Zugriff
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
# Feldliste der Kollektion
fields:
- name: status
type: string
meta:
label:
de: Status
en: Status
widget: select
choices:
- name: open
id: open
- name: login
id: login
- name: password
type: string
meta:
label:
de: Passwort
en: Password

View File

@@ -0,0 +1,24 @@
name: sizingDetails
meta:
allowExportAll: true
label:
de: Größen Details
en: Sizing Details
muiIcon: label
views: []
permissions:
public:
methods:
get: true
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields: []

66
api/collections/ssr.yml Normal file
View File

@@ -0,0 +1,66 @@
########################################################################
# SSR Dummy collections
########################################################################
name: ssr
meta:
label: { de: "SSR Dummy", en: "ssr dummy" }
muiIcon: server
rowIdentTpl: { twig: "{{ id }}" }
views:
- type: simpleList
mediaQuery: "(max-width: 600px)"
primaryText: id
secondaryText: insertTime
tertiaryText: path
- type: table
columns:
- id
- insertTime
- source: path
filter: true
- source: validUntil
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: true
post: false
put: false
delete: true
hooks:
get:
read:
type: javascript
file: hooks/ssr/get_read.js
post:
bind:
type: javascript
file: hooks/ssr/post_bind.js
fields:
- name: path
type: string
index: [single, unique]
- name: content
type: string
meta:
inputProps:
multiline: true
- name: validUntil
type: date
index: [single]
meta:
label:
de: Gültig bis
en: Valid until

54
api/collections/tag.yml Normal file
View File

@@ -0,0 +1,54 @@
name: tag
uploadPath: ../media/tag
meta:
allowExportAll: true
label:
de: Tags
en: Tags
muiIcon: label
defaultSort:
field: name
order: ASC
views: &views
- type: table
columns:
- source: name
filter: true
subNavigation:
- name: modalForeign
defaultSort:
field: name
order: ASC
views: *views
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- name: name
type: string
meta:
label:
de: Name
en: Name

View File

@@ -0,0 +1,92 @@
########################################################################
# Webhooks
########################################################################
name: webhook
meta:
openapi:
disabled: true
label: { de: "Webhooks", en: "webhooks" }
muiIcon: http
rowIdentTpl: { twig: "{{ insertTime }} - {{ type }}" }
views:
- type: simpleList
mediaQuery: "(max-width: 600px)"
primaryText: type
secondaryText: scope
- type: table
columns:
- type
- scope
- active
permissions:
public:
methods:
get: false
post: true
put: false
delete: false
user:
methods:
get: true
post: true
put: false
delete: false
"token:${BIGCOMMERCE_WEBHOOK_TOKEN}":
methods:
get: true
post: true
put: false
delete: false
hooks:
post:
create:
type: javascript
file: hooks/webhook/post_create.js
put:
update:
type: javascript
file: hooks/webhook/put_update.js
delete:
delete:
type: javascript
file: hooks/webhook/delete_delete.js
fields:
- name: type
type: string
meta:
label: { de: "Typ", en: "Type" }
widget: select
choices:
- id: "bigCommerce"
name: "BigCommerce"
- id: "printful"
name: "Printful"
- name: scope
type: string
meta:
label: { de: "Scope", en: "Scope" }
helperText:
de: "The scope of the webhook, for example: store/product/*"
en: "The scope of the webhook, for example: store/product/*"
- name: active
type: boolean
meta:
label: { de: "Aktiv", en: "Active" }
helperText:
de: "Aktiviert oder deaktiviert den Webhook"
en: "Enables or disables the webhook"
- name: webhookId
type: number
meta:
label: { de: "Webhook ID", en: "Webhook ID" }
helperText:
de: "Die ID des Webhooks"
en: "The ID of the webhook"
inputProperties:
disabled: true

View File

@@ -0,0 +1,36 @@
########################################################################
# cart
########################################################################
name: dummyWishlistEntryEndpoint
meta:
hideInNavigation: true
openapi:
disabled: true
permissions:
public:
methods:
get: true
post: true
put: false
delete: false
user:
methods:
get: false
post: false
put: false
delete: false
hooks:
get:
read:
type: javascript
file: hooks/wishlist/get_read.js
post:
validate:
type: javascript
file: hooks/wishlist/post_create.js
fields:

61
api/config.yml Normal file
View File

@@ -0,0 +1,61 @@
namespace: bkdf_tibi_2024
meta:
openapi:
servers:
- url: https://tibi-admin-server.code.testversion.online/api/v1/_/demo
description: code-server
dashboard: !include helper/dashboard.yml
injectIntoHead:
# inject font faces (not possible in shadow dom for preview)
- eval: |
"<link rel='stylesheet' href='" + $projectBase + "_/assets/variables/variables.css'>"
- eval: |
"<link rel='stylesheet' href='" + $projectBase + "_/assets/fonts/fonts.css'>"
# Liste möglicher Berechtigungen, die Benutzern zugeordnet werden können
permissions:
- name: pages
label:
de: Seiten
en: Pages
collections:
- !include collections/bigCommerceOrder.yml
- !include collections/OrderReturnRequest.yml
- !include collections/OrderRevokeRequest.yml
- !include collections/contact.yml
- !include collections/rating.yml
- !include collections/bigCommerceProduct.yml
- !include collections/bigCommerceCustomer.yml
- !include collections/QRCode.yml
- !include collections/productBenefit.yml
- !include collections/banner.yml
- !include collections/content.yml
- !include collections/selfImprovementChapter.yml
- !include collections/Challenge.yml
- !include collections/medialib.yml
- !include collections/navigation.yml
- !include collections/sizingDetails.yml
- !include collections/lookCombination.yml
- !include collections/tag.yml
- !include collections/webhook.yml
- !include collections/login.yml
- !include collections/action.yml
- !include collections/wishlistEntry.yml
- !include collections/module.yml
- !include collections/helpcenterChapter.yml
- !include collections/shopStatus.yml
- !include collections/productBackgroundImage.yml
- !include collections/ssr.yml
- !include collections/lighthouseSubpath.yml
- !include collections/lighthouse.yml
- !include collections/dummyCartEndpoint.yml
- !include collections/backups.yml
jobs:
- !include jobs/lighthouse.yml
assets:
- !include assets/logo.yml
- !include assets/dist.yml
- !include assets/fonts.yml
- !include assets/variables.yml

3
api/config.yml.env Normal file
View File

@@ -0,0 +1,3 @@
TOKEN=geheim
SSR_TOKEN=owshwerNwoa
BIGCOMMERCE_WEBHOOK_TOKEN=super_secure_and_extremely_secret_big_commerce_webhook_token_123

41
api/helper/dashboard.yml Normal file
View File

@@ -0,0 +1,41 @@
majorItems:
- type: "sectionTitle"
title: { de: "Seiteninhalte", en: "Page content" }
- collection: orderReturnRequest
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: orderRevokeRequest
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: bigCommerceCustomer
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: rating
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: contact
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- collection: qrCode
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
minorItems: []

View File

@@ -0,0 +1,138 @@
const { frontendBase, jwtSecret, logoPath, noReplyEmail, operatorEmail, serverBaseURL } = require("../config")
const { getCustomerById } = require("../lib/bigcommerceRestAPI")
const { createNewsletterSubscriber, checkIfNewsletterSubscriber } = require("../lib/omnisendRestApi")
const { cryptchaCheck } = require("../lib/utils")
;(function () {
const operation = context.data.operation
if (operation === "requestPasswordReset") {
cryptchaCheck()
requestPasswordReset()
} else if (operation === "checkUsernameTaken") {
const username = context.data.username
const user = context.db.find("bigCommerceCustomer", {
filter: { username: username.toLowerCase() },
})[0]
throw {
status: 200,
data: !!user,
}
} else if (operation === "reportRecord") {
const customerId = context.data.customerId
if (!customerId) {
throw {
status: 400,
message: "customerId is required",
}
}
const recordTitle = context.data.record
context.smtp.sendMail({
to: operatorEmail,
from: noReplyEmail,
fromName: "BinKrassDuFass",
replyTo: noReplyEmail,
subject: "Record Reported",
plain: "Record reported, customer ID: " + customerId + ", record: " + recordTitle,
})
throw {
status: 200,
message: "Record reported",
}
} else if (operation === "subscribeToNewsletter") {
if (!context.data.email) {
throw {
status: 400,
message: "Email is required",
}
}
createNewsletterSubscriber(context.data.email?.toLowerCase())
throw {
status: 200,
message: "Newsletter subscriber created",
}
} else if (operation === "checkIfNewsletterSubscriber") {
const email = context.data.email
const isSubscriber = checkIfNewsletterSubscriber(email.toLowerCase())
throw {
status: 200,
data: isSubscriber,
}
}
})()
/**
*
* @param {string} tibiId
* @param {string} bigCommerceId
* @param {string} key
* @returns {string}
*/
function buildPwResetToken(tibiId, bigCommerceId, key) {
return context.jwt.create(
{
tibiId: tibiId,
bigCommerceId: bigCommerceId,
check: key,
},
{
secret: jwtSecret,
validityDuration: 60 * 60 * 24 * 90, // 90 days
}
)
}
function requestPasswordReset() {
const random256BitString = Math.random().toString(36).substring(2, 34)
const email = context.data.email
if (!email) {
throw {
status: 400,
message: "Email is required",
}
}
let customer = context.db.find("bigCommerceCustomer", {
filter: { email: email?.toLowerCase() },
})[0]
if (!customer) {
const customerBigCommerce = getCustomerById(null, email)
if (!customerBigCommerce) {
throw {
status: 404,
message: "Customer not found",
}
}
const username = customerBigCommerce.form_fields.find((field) => field.name === "username")?.value
customer = context.db.create("bigCommerceCustomer", {
bigCommerceId: customerBigCommerce.id,
email: customerBigCommerce.email.toLowerCase(),
username: username ? username?.toLowerCase() : Math.random().toString(36).substring(2, 15),
})
}
const pwResetToken = buildPwResetToken(customer.id, customer.bigCommerceId, random256BitString)
const store = {
logo: `${serverBaseURL}${logoPath}`,
frontendBase,
pwReset: `${frontendBase}profile/reset-password?token=${pwResetToken}`,
}
const html = context.tpl.execute(context.fs.readFile("templates/requestPWReset.html"), {
store,
})
context.smtp.sendMail({
to: email,
from: operatorEmail,
fromName: "BinKrassDuFass",
replyTo: noReplyEmail,
subject: "Passwort Zurücksetzen",
html,
})
context.db.update("bigCommerceCustomer", customer.id, {
currentToken: random256BitString,
})
throw {
status: 200,
message: "Password reset email sent",
}
}

View File

@@ -0,0 +1,112 @@
;(function () {
let backup = context.data
const updateLogs = compareAndUpdateEntry(backup?.entry, backup?.collectionName, backup?.versionNr - 1)
backup.updateLogs = updateLogs
return { data: backup }
/**
*
* @param {Object} entry
* @param {string} collectionName
* @param {number} versionNr
* @returns
*/
function compareAndUpdateEntry(entry, collectionName, versionNr) {
let updateLogs
if (versionNr == 0) {
updateLogs = getUpdateLogs({}, entry)
}
delete entry.updateTime
let previousEntry = context.db.find("backups", {
filter: { entryId: context.data.entryId, versionNr, collectionName },
})[0]
if (!previousEntry) {
console.error("No previous entry found")
updateLogs = getUpdateLogs({}, entry)
} else {
delete previousEntry.updateTime
updateLogs = getUpdateLogs(previousEntry.entry, entry)
}
console.log(context.json.stringify(previousEntry?.entry), context.json.stringify(entry))
return updateLogs
}
/**
*
* @param {any[]} array
* @returns {any[]}
*/
function filterValidObjects(array) {
return array.filter((object) => {
for (let key in object) {
if (typeof object[key] !== "string" && object[key] !== null) {
return false
}
}
return true
})
}
/**
*
* @param {Object} oldObj
* @param {Object} newObj
* @param {string} path
* @returns {any[]}
*/
function getUpdateLogs(oldObj = {}, newObj = {}, path = "") {
let updateLogs = []
const ignoredKeys = ["id", "insertTime", "updateTime"]
const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)])
allKeys.forEach((key) => {
if (ignoredKeys.includes(key)) return
const newPath = path ? `${path}.${key}` : key
const oldVal = oldObj.hasOwnProperty(key) ? oldObj[key] : ""
const newVal = newObj.hasOwnProperty(key) ? newObj[key] : ""
// Handle Arrays
if (Array.isArray(oldVal) || Array.isArray(newVal)) {
const oldArr = oldVal || []
const newArr = newVal || []
for (let i = 0; i < Math.max(oldArr.length, newArr.length); i++) {
const itemPath = `${newPath}[${i}]`
if (oldArr[i] !== newArr[i]) {
if (typeof oldArr[i] === "object" || typeof newArr[i] === "object") {
const arrUpdates = getUpdateLogs(oldArr[i], newArr[i], itemPath)
updateLogs = updateLogs.concat(arrUpdates)
} else {
updateLogs.push({
field: itemPath,
previous: oldArr[i] === undefined ? "" : oldArr[i].toString(),
current: newArr[i] === undefined ? "" : newArr[i].toString(),
})
}
}
}
}
// Handle nested objects but not arrays
else if (
(typeof oldVal === "object" && oldVal !== null) ||
(typeof newVal === "object" && newVal !== null)
) {
const nestedUpdates = getUpdateLogs(oldVal || {}, newVal || {}, newPath)
updateLogs = updateLogs.concat(nestedUpdates)
}
// Handle primitive types
else if (oldVal !== newVal) {
updateLogs.push({
field: newPath,
previous: oldVal?.toString(),
current: newVal?.toString(),
})
}
})
return filterValidObjects(updateLogs)
}
})()

View File

@@ -0,0 +1,46 @@
const { getCart, getRedirectUrl } = require("../lib/bigcommerceRestAPI")
const { bigcommerceStoreHash, bigcommerceBaseURL, bigCommerceCliendId, bigCommerceClientSecret } = require("../config")
const { getCustomerById, getLoginUrl } = require("../lib/bigcommerceRestAPI")
const { withAccount } = require("../lib/utils")
const { mapRestApiCartToGraphQL } = require("./helper")
;(function () {
if (context.user.auth()) return {}
const checkout = context.request().query("checkout")
const loggedInCheckout = context.request().query("loggedInCheckout")
if (checkout) {
if (loggedInCheckout) {
withAccount((loginClaims) => {
const cartId = context.request().param("id")
const cart = getCart(cartId)
const { checkoutURL } = getRedirectUrl(cartId)
const loginUrl = getLoginUrl(
loginClaims.bigCommerceId,
bigcommerceStoreHash,
bigcommerceBaseURL,
bigCommerceCliendId,
bigCommerceClientSecret,
checkoutURL.split(bigcommerceBaseURL).pop()
)
throw {
status: 200,
data: cart && {
cart: mapRestApiCartToGraphQL(cart),
checkoutURL: loginUrl,
},
}
})
}
}
const cartId = context.request().param("id")
const cart = getCart(cartId)
const { checkoutURL, embeddedCheckoutURL } = getRedirectUrl(cartId)
throw {
status: 200,
data: cart && {
cart: mapRestApiCartToGraphQL(cart),
checkoutURL: checkoutURL,
embeddedCheckoutURL: embeddedCheckoutURL,
},
}
})()

53
api/hooks/cart/helper.js Normal file
View File

@@ -0,0 +1,53 @@
/**
*
* @param {RestApiCart} cart
* @returns {BigCommerceCart}
*/
function mapRestApiCartToGraphQL(cart) {
return {
entityId: cart.id,
currencyCode: cart.currency.code,
isTaxIncluded: cart.tax_included,
baseAmount: { value: cart.base_amount, currencyCode: cart.currency.code },
discountedAmount: { value: cart.discount_amount, currencyCode: cart.currency.code },
amount: { value: cart.cart_amount, currencyCode: cart.currency.code },
discounts: cart.discounts.map((d) => ({
entityId: d.id,
discountedAmount: { value: d.discounted_amount, currencyCode: cart.currency.code },
})),
lineItems: {
physicalItems: cart.line_items.physical_items.map((item) => ({
entityId: item.id,
parentEntityId: cart.parent_id,
productEntityId: item.product_id,
variantEntityId: item.variant_id,
sku: item.sku,
name: item.name,
url: item.url,
imageUrl: item.image_url,
brand: "BKDF", // REST API does not provide brand directly
quantity: item.quantity,
isTaxable: item.is_taxable,
listPrice: { value: item.list_price, currencyCode: cart.currency.code },
extendedListPrice: { value: item.extended_list_price, currencyCode: cart.currency.code },
selectedOptions: item?.options?.map((option) => ({
// Map each option to the GraphQL format
// Assuming a simplified structure here for the example
})),
isShippingRequired: true, // Example assumption
})),
digitalItems: [],
customItems: [],
giftCertificates: [],
totalQuantity: cart.line_items.physical_items.reduce((total, item) => total + item.quantity, 0),
},
createdAt: { utc: new Date(cart.created_time) },
updatedAt: { utc: new Date(cart.updated_time) },
locale: cart.locale,
}
}
module.exports = {
mapRestApiCartToGraphQL,
}

View File

@@ -0,0 +1,25 @@
const { addCartItem, updateCartItem, deleteCartItem, getCart } = require("../lib/bigcommerceRestAPI")
const { postAddToCart } = require("../lib/facebookRestAPI")
;(function () {
const operation = context?.data?.operation
if (operation == "add") {
addCartItem(context?.data?.cartId, context?.data?.lineItems)
try {
postAddToCart()
} catch (e) {}
} else if (operation == "update") {
updateCartItem(context?.data?.cartId, context?.data?.lineItem, context?.data?.entityId)
try {
postAddToCart()
} catch (e) {}
} else if (operation == "delete") {
deleteCartItem(context?.data?.cartId, context?.data?.entityId)
}
throw {
status: 200,
message: "success",
}
})()

5
api/hooks/clear_cache.js Normal file
View File

@@ -0,0 +1,5 @@
var utils = require("./lib/utils")
;(function () {
utils.clearSSRCache()
})()

View File

@@ -0,0 +1,59 @@
const release = "binkrassdufass.dirty"
const apiClientBaseURL = "/api/"
const originURL = "https://bkdf-tibi-2024.code.testversion.online"
const cryptchaSiteId = "66cb701e093846000151707e"
// @ts-ignore
if (release && typeof context !== "undefined") {
context.response.header("X-Release", release)
}
/**
*
* @param {number} price
* @param {number} quantity
* @returns {number|string}
*/
function formatPrice(price, quantity = 1) {
const newPrice = Math.floor((Math.round(price * 100) / 100) * quantity)
return newPrice.toFixed(2) + " €"
}
const daysForReturn = 30
const daysToArrive = 3
/**
*
* @param {Date} countdownStart
* @returns {Date}
*/
function getLastDayForReturn(countdownStart) {
const date = new Date(countdownStart)
date.setDate(date.getDate() + daysForReturn + daysToArrive)
return date
}
/**
*
* @param {Date} countdownStart
* @returns {boolean}
*/
function checkIfOrderMayArrived(countdownStart) {
const date = new Date(countdownStart)
date.setDate(date.getDate() + daysToArrive)
return date < new Date()
}
module.exports = {
release,
apiClientBaseURL,
frontendBase: "https://binkrassdufass.de/",
tibiUrl: "https://dev.tibicms.de",
bkdfApiUrl: "https://binkrassdufass.de/api/",
originURL,
cryptchaSiteId,
formatPrice,
daysForReturn: daysForReturn,
getLastDayForReturn,
daysToArrive,
checkIfOrderMayArrived,
}

55
api/hooks/config.js Normal file
View File

@@ -0,0 +1,55 @@
const apiSsrBaseURL = "http://localhost:8080/api/v1/_/bkdf_tibi_2024/"
const { frontendBase, tibiUrl } = require("./config-client")
module.exports = {
operatorEmail: "info@binkrassdufass.de",
operatorName: "BinKrassDuFass",
contactEmail: "support@binkrassdufass.de",
noReplyEmail: "noreply@binkrassdufass.de",
frontendBase,
apiBase: frontendBase + "/api/",
tibiUrl,
apiSsrBaseURL,
ssrValidatePath: function (/** @type {string} */ path) {
// validate if path ssr rendering is ok, -1 = NOTFOUND, 0 = NO SSR, 1 = SSR
// pe. use context.readCollection("product", {filter: {path: path}}) ... to validate dynamic urls
// // / is de home
// if (path == "/") return 1
// // all other sites are in db
//path = path?.replace(/^\//, "")
if (path.includes("profile") || path.includes("@") || path.includes("redirectToProfile")) return 0
const resp = context.db.find("content", {
filter: {
$and: [{ $or: [{ path }, { "alternativePaths.path": path }] }],
},
selector: { _id: 1 },
})
if (resp && resp.length) {
return 1
}
// not found
return -1
},
ssrPublishCheckCollections: ["content"],
LIGHTHOUSE_TOKEN: "AIzaSyC0UxHp3-MpJiDL3ws7pEV6lj57bfIc7GQ",
bigcommerceApiOAuth: "92tgx3by44vmizj6gu1ev4jjdjqu2rb",
serverBaseURL: "https://www.binkrassdufass.de/api/", // "https://bkdf-tibi-2024-tibiserver.code.testversion.online/api/v1/_/bkdf_tibi_2024/", // LIVE:
bigcommerceStoreHash: "punbvyqteo",
channelId: 1578456,
channelName: "BinKrassDuFass",
logoPath: "_/assets/logo/logo-white.svg",
jwtSecret: "7456ztjihugf@@ofg#iehuifdnfgobvcxsdafa+rpeertuhbfgnvcxfasdijnfvdssecretodhxfgoidfsjgpias",
masterPassword: "ycxfvöklpcxylkäpöcdsyüäp#öldsa#öpü+äAds#+äüööü+ä#pcxdsäö.#cvx.vl,bcxlvöä,cbkmköldfgoplü+fsda",
DeepLkey: "1a248829-fcd8-40e2-8437-c3fa1d2a416e",
jwtValidityDuration: 600,
bigCommerceCliendId: "3zx5dwd9n9h7w72d2yg8845g2b28m5x",
bigCommerceClientSecret: "444dc8e9ce6fea29110cff1238a952f4b807655c1b1175cbbea8bd039e236e7d",
omnisendApiKey: "6682ded7516e60cf4800023f-HHGGCOm2tCuPdb81NLo3K018AjqekWL3gFGWlNWae08NbJbdk2",
bigcommerceBaseURL: "https://store-punbvyqteo.mybigcommerce.com",
fb_accessToken:
"EAA2c78abUOoBOxX9IPbHZBSJ6rZA0tqpv6jkZCCRzZA6OvIHkTbl9h02MwoBKu8ZAqFGfYFSOXV0nBwNJ9f6319PyGdtfUrfpECZCdQj1a6cAJJaKxcguSDNVMYr5aSQ1UlovOGaaQeMzwVUW1LKzx3KFq1m7Vwl30xTMjQTaQSYVk9zIoTlySqv2pFZBZAuCasPsAZDZD",
printfulAPIToken: "dtHTQ8JMe4eeBklIIfcZf2YHtq3NgKhwmhIC7FND",
}

View File

@@ -0,0 +1,8 @@
const { cryptchaCheck } = require("../lib/utils")
;(function () {
throw {
status: 500,
data: "Hello, World!",
}
cryptchaCheck()
})()

Some files were not shown because too many files have changed in this diff Show More