diff --git a/api/collections/articles.yml b/api/collections/articles.yml
index c18e989..7e8678b 100644
--- a/api/collections/articles.yml
+++ b/api/collections/articles.yml
@@ -6,7 +6,7 @@ name: articles
uploadPath: ../media/articles
meta:
# Navigationseintrag in der Admin-UI
- label: { de: "Artikel auf der Seite", en: "Page articles" }
+ label: { de: "Artikel", en: "Articles" }
# Icon (Material UI) für den Navigationseintrag
muiIcon: file-document-edit-outline
# Standardsortierung der Liste
@@ -19,18 +19,18 @@ meta:
mediaQuery: "(max-width:599px)"
primaryText: path
columns:
- - article.general.public
- - article.content.title
- - article.general.position
- - article.general.sort
+ - article.general.public
+ - article.content.title
+ - article.general.position
+ - article.general.sort
# Desktop
- type: table
mediaQuery: "(min-width:600px)"
columns:
- - article.general.public
- - article.content.title
- - article.general.position
- - article.general.sort
+ - article.general.public
+ - article.content.title
+ - article.general.position
+ - article.general.sort
imageFilter:
xs:
@@ -100,4 +100,4 @@ permissions:
# file: hooks/article/delete_return.js
fields:
- - !include _article.yml
\ No newline at end of file
+ - !include _article.yml
diff --git a/api/collections/fields/_article.yml b/api/collections/fields/_article.yml
new file mode 100644
index 0000000..e4ba93d
--- /dev/null
+++ b/api/collections/fields/_article.yml
@@ -0,0 +1,359 @@
+name: article
+type: object
+meta:
+ widget: tabs
+ label:
+ de: Einstellungen zum Artikel
+ en: Article Setings
+ activeTab: 1
+subFields:
+ - name: general
+ type: object
+ meta:
+ label:
+ de: Allgemein
+ en: General
+ css:
+ subFields:
+ - name: public
+ type: boolean
+ meta:
+ label:
+ de: Veröffentlicht
+ en: Public
+ helperText:
+ de: "Der Artikel wird auf der Seite angezeigt."
+ en: "This article is displayed on the page."
+ - name: publish_date
+ type: object
+ meta:
+ label:
+ de: Datum der Veröffentlichung
+ en: Release Date
+ css: "grid grid-50"
+ subFields:
+ - name: from
+ type: date
+ meta:
+ inputProps:
+ type: "datetime-local"
+ label:
+ de: Datum (ab)
+ en: Date (from)
+ - name: until
+ type: date
+ meta:
+ inputProps:
+ type: "datetime-local"
+ label:
+ de: Datum (bis)
+ en: Date (until)
+ - name: position
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Position auf der Seite
+ en: Position on page
+ defaultValue: []
+ choices:
+ - { id: "content", name: { de: "Inhaltsbereich", en: "Content Area" } }
+ - { id: "sidebar", name: { de: "Sidebar", en: "Sidebar" } }
+ - name: categories
+ type: string[]
+ meta:
+ widget: chipArray
+ label:
+ de: Position auf der Seite
+ en: Position on page
+ defaultValue: ["c1"]
+ autocomplete: true
+ choices:
+ - { id: "c1", name: { de: "Category 1", en: "" } }
+ - { id: "c2", name: { de: "Category Number 2", en: "" } }
+ - { id: "c3", name: { de: "Best Category 3", en: "" } }
+ - name: sort
+ type: number
+ meta:
+ inputProps:
+ type: number
+ placeholder: 0
+ label: { de: "Sortierung", en: "Sorting" }
+ helperText:
+ de: "1...5...10...100"
+ en: "1...5...10...100"
+ - name: content
+ type: object
+ meta:
+ label:
+ de: Inhalt
+ en: Content
+ css:
+ subFields:
+ - name: slug
+ type: string
+ meta:
+ label: { de: "Permalink", en: "Permalink" }
+ - name: title
+ type: string
+ meta:
+ label: { de: "Titel", en: "Title" }
+ - name: subtitle
+ type: string
+ meta:
+ label: { de: "Untertitel", en: "Subtitle" }
+ - name: types
+ type: object
+ meta:
+ widget: tabs
+ label:
+ de: Inhalt dieses Artikel
+ en: Article Content
+ activeTab: 0
+ subFields:
+ - name: teaser
+ type: string
+ meta:
+ widget: richtext
+ label: { de: "Teaser-Text des Artikel", en: "Article Teaser Text" }
+ - name: details
+ type: string
+ meta:
+ widget: richtext
+ label: { de: "Detail-Text des Artikel", en: "Article Detail Text" }
+ - name: contentMedia
+ type: object
+ meta:
+ label:
+ de: Medien
+ en: Media
+ css:
+ subFields:
+ - name: mediaFiles
+ type: object[]
+ meta:
+ label: { de: "Bilder", en: "Images" }
+ subFields:
+ - name: title
+ type: string
+ meta:
+ label: { de: "Datei-Titel", en: "File Title" }
+ - name: alternateText
+ type: string
+ meta:
+ label: { de: "Alternativer Text", en: "Alternate Text" }
+ - name: id
+ type: string
+ meta:
+ label: { de: "Technischer Name / ID", en: "Technical name / ID" }
+ - name: file
+ type: file
+ meta:
+ widget: image
+ label: { de: "Datei", en: "File" }
+ - name: caption
+ type: string
+ meta:
+ label: { de: "Bildunterschrift", en: "Caption" }
+ - name: contentAttachments
+ type: object
+ meta:
+ label:
+ de: Anhänge / Downloads
+ en: Attachments / Downloads
+ css:
+ subFields:
+ - name: attachments
+ type: object[]
+ meta:
+ label: { de: "Anhänge", en: "Attachments" }
+ subFields:
+ - name: title
+ type: string
+ meta:
+ label: { de: "Datei-Titel", en: "File Title" }
+ - name: id
+ type: string
+ meta:
+ label: { de: "Technischer Name / ID", en: "Technical name / ID" }
+ - name: file
+ type: file
+ meta:
+ label: { de: "", en: "" }
+ - name: layout
+ type: object
+ meta:
+ widget: tabs
+ label:
+ de: Layout
+ en: Layout
+ css:
+ subFields:
+ - name: variant
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Erscheinungsbild
+ en: Appearance
+ defaultValue: ["_self"]
+ choices:
+ - { id: "top", name: { de: "Artikelbild oben (volle Breite)", en: "Article picture top (full width)" } }
+ - { id: "right", name: { de: "Artikelbild rechts (volle Höhe)", en: "Article picture right (full height)" } }
+ - { id: "bottom", name: { de: "Artikelbild unten (volle Breite)", en: "Article picture left (full width)" } }
+ - { id: "left", name: { de: "Artikelbild links (volle Höhe)", en: "Article picture left (full height)" } }
+ - { id: "after-teaser", name: { de: "Artikelbild unter Teaser (volle Breite)" , en: "Article picture under teaser (full width)" } }
+ - { id: "top-left", name: { de: "Artikelbild oben links", en: "Article picture above left" } }
+ - { id: "top-right", name: { de: "Artikelbild oben rechts", en: "Article picture above right" } }
+ - { id: "bottom-left", name: { de: "Artikelbild unten links", en: "Article picture below left" } }
+ - { id: "bottom-right", name: { de: "Artikelbild unten rechts", en: "Article picture below right" } }
+ - name: margin
+ type: object
+ meta:
+ label: { de: "Abstand nach außen (Margin)", en: "Distance to the outside (Margin)" }
+ subFields:
+ - name: top
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Oben
+ en: Top
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "mt-xs", name: "Sehr kleiner Abstand" }
+ - { id: "mt-sm", name: "Kleiner Abstand" }
+ - { id: "mt-md", name: "Normal" }
+ - { id: "mt-lg", name: "Großer Abstand" }
+ - { id: "mt-xl", name: "Sehr großer Abstand" }
+ - name: right
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Rechts
+ en: Right
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "mr-xs", name: "Sehr kleiner Abstand" }
+ - { id: "mr-sm", name: "Kleiner Abstand" }
+ - { id: "mr-md", name: "Normal" }
+ - { id: "mr-lg", name: "Großer Abstand" }
+ - { id: "mr-xl", name: "Sehr großer Abstand" }
+ - name: bottom
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Unten
+ en: Bottom
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "mb-xs", name: "Sehr kleiner Abstand" }
+ - { id: "mb-sm", name: "Kleiner Abstand" }
+ - { id: "mb-md", name: "Normal" }
+ - { id: "mb-lg", name: "Großer Abstand" }
+ - { id: "mb-xl", name: "Sehr großer Abstand" }
+ - name: left
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Links
+ en: Left
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "ml-xs", name: "Sehr kleiner Abstand" }
+ - { id: "ml-sm", name: "Kleiner Abstand" }
+ - { id: "ml-md", name: "Normal" }
+ - { id: "ml-lg", name: "Großer Abstand" }
+ - { id: "ml-xl", name: "Sehr großer Abstand" }
+ - name: padding
+ type: object
+ meta:
+ label: { de: "Abstand nach innen (Padding)", en: "Distance inside (Padding)" }
+ subFields:
+ - name: top
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Oben
+ en: Top
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "pt-xs", name: "Sehr kleiner Abstand" }
+ - { id: "pt-sm", name: "Kleiner Abstand" }
+ - { id: "pt-md", name: "Normal" }
+ - { id: "pt-lg", name: "Großer Abstand" }
+ - { id: "pt-xl", name: "Sehr großer Abstand" }
+ - name: right
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Rechts
+ en: Right
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "pr-xs", name: "Sehr kleiner Abstand" }
+ - { id: "pr-sm", name: "Kleiner Abstand" }
+ - { id: "pr-md", name: "Normal" }
+ - { id: "pr-lg", name: "Großer Abstand" }
+ - { id: "pr-xl", name: "Sehr großer Abstand" }
+ - name: bottom
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Unten
+ en: Bottom
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "pb-xs", name: "Sehr kleiner Abstand" }
+ - { id: "pb-sm", name: "Kleiner Abstand" }
+ - { id: "pb-md", name: "Normal" }
+ - { id: "pb-lg", name: "Großer Abstand" }
+ - { id: "pb-xl", name: "Sehr großer Abstand" }
+ - name: left
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Links
+ en: Left
+ choices:
+ - { id: "", name: "Kein Abstand" }
+ - { id: "pl-xs", name: "Sehr kleiner Abstand" }
+ - { id: "pl-sm", name: "Kleiner Abstand" }
+ - { id: "pl-md", name: "Normal" }
+ - { id: "pl-lg", name: "Großer Abstand" }
+ - { id: "pl-xl", name: "Sehr großer Abstand" }
+ - name: link
+ type: object
+ meta:
+ label:
+ de: Verlinkung
+ en: Link
+ css:
+ subFields:
+ - name: url
+ type: string
+ meta:
+ label: { de: "Ziel-URL", en: "Target URL" }
+ - name: text
+ type: string
+ meta:
+ label: { de: "Link-Beschriftung", en: "Link-Text" }
+ - name: target
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Zielfenster
+ en: Target
+ defaultValue: ["_self"]
+ choices:
+ - { id: "_self", name: "(Standardwert) gleicher Tab oder Seite" }
+ - { id: "_blank", name: "Neuer Tab oder Fenster" }
+ - { id: "_parent", name: "Elternfenster" }
diff --git a/api/collections/galleries.yml b/api/collections/galleries.yml
new file mode 100644
index 0000000..39783d4
--- /dev/null
+++ b/api/collections/galleries.yml
@@ -0,0 +1,127 @@
+###############################################################
+# Galleries
+###############################################################
+
+# Name/URL-Anteil der Kollektion
+name: galleries
+uploadPath: ../media/galleries
+
+# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
+meta:
+ # Navigationseintrag in der Admin-UI
+ label: { de: "Galerien", en: "Galleries" }
+ # Icon (Material UI) für den Navigationseintrag
+ muiIcon: image-multiple-outline
+ # Identifizierung eines Eintrags für z.B. Select-Boxen in der Admin-UI
+ rowIdentTpl: { twig: "{{ path }}" }
+ # Standardsortierung der Liste
+ defaultSort: { field: "path", order: "ASC" }
+ # Admin-Backend Ansichten
+ defaultImageFilter: s
+ views:
+ # Mobile Darstellung
+ - type: simpleList
+ mediaQuery: "(max-width:599px)"
+ primaryText: name
+ columns:
+ - name
+ - variant
+ # Desktop
+ - type: table
+ mediaQuery: "(min-width:600px)"
+ columns:
+ - name
+ - variant
+
+imageFilter:
+ xs:
+ - fit: true
+ height: 90
+ width: 90
+ resampling: lancos
+ quality: 60
+ s:
+ - fit: true
+ height: 300
+ width: 300
+ resampling: lancos
+ quality: 60
+ m:
+ - fit: true
+ height: 600
+ width: 600
+ resampling: lancos
+ quality: 60
+ l:
+ - fit: true
+ height: 1200
+ width: 1200
+ resampling: lancos
+ quality: 60
+ xl:
+ - fit: true
+ height: 2000
+ width: 2000
+ resampling: lancos
+ quality: 60
+
+permissions:
+ public:
+ methods:
+ get: true
+ 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: false
+ put: false
+ delete: false
+
+# Feldliste der Kollektion
+fields:
+ - name: name
+ type: string
+ meta:
+ label: { de: "Name der Galerie", en: "Gallery Name" }
+ - name: variant
+ type: string
+ meta:
+ widget: select
+ label:
+ de: Erscheinungsbild
+ en: Appearance
+ defaultValue: ["default"]
+ choices:
+ - { id: "default", name: { de: "Standard", en: "Default" } }
+ - { id: "simple-with-title", name: { de: "Einfach mit Titel", en: "Simple with title" } }
+ - name: items
+ type: object[]
+ meta:
+ label: { de: "Bilder der Galerie", en: "Gallery Images" }
+ subFields:
+ - name: file
+ type: file
+ meta:
+ widget: image
+ label: { de: "Datei", en: "File" }
+ - name: title
+ type: string
+ meta:
+ label: { de: "Titel", en: "Title" }
+ - name: description
+ type: string
+ meta:
+ label: { de: "Beschreibung", en: "Description" }
+ - name: alt
+ type: string
+ meta:
+ label: { de: "Alternativer Text", en: "Alternative caption" }
diff --git a/api/collections/mediaLibrary.yml b/api/collections/mediaLibrary.yml
new file mode 100644
index 0000000..ecdc780
--- /dev/null
+++ b/api/collections/mediaLibrary.yml
@@ -0,0 +1,91 @@
+###############################################################
+# Media Library
+###############################################################
+
+# Name/URL-Anteil der Kollektion
+name: media-library
+uploadPath: ../media/media-library
+
+# Metaangaben zur Kollektion welche in der Admin-UI verwendet werden können
+meta:
+ # Navigationseintrag in der Admin-UI
+ label: { de: "Medien", en: "Media Library" }
+ # Icon (Material UI) für den Navigationseintrag
+ muiIcon: file-document-multiple
+ # Identifizierung eines Eintrags für z.B. Select-Boxen in der Admin-UI
+ rowIdentTpl: { twig: "{{ path }}" }
+ # Standardsortierung der Liste
+ defaultSort: { field: "path", order: "ASC" }
+ # Admin-Backend Ansichten
+ defaultImageFilter: s
+ views:
+ - type: mediaLibrary
+ mediaQuery: "(min-width:0px)"
+ columns:
+ - file
+ - title
+
+imageFilter:
+ xs:
+ - fit: true
+ height: 90
+ width: 90
+ resampling: lanczos
+ quality: 60
+ s:
+ - fit: true
+ height: 300
+ width: 300
+ resampling: lanczos
+ quality: 60
+ m:
+ - fit: true
+ height: 600
+ width: 600
+ resampling: lanczos
+ quality: 60
+ l:
+ - fit: true
+ height: 1200
+ width: 1200
+ resampling: lanczos
+ quality: 60
+ xl:
+ - fit: true
+ height: 2000
+ width: 2000
+ resampling: lanczos
+ quality: 60
+
+permissions:
+ public:
+ methods:
+ get: true
+ 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: false
+ put: false
+ delete: false
+
+# Feldliste der Kollektion
+fields:
+ - name: file
+ type: file
+ meta:
+ widget: mediaLibraryFile
+ label: { de: "Datei", en: "File" }
+ - name: title
+ type: string
+ meta:
+ label: { de: "Titel des Dokuments/Bild", en: "Document/Image Title" }
diff --git a/api/config.yml b/api/config.yml
index ef55585..cfab0c0 100644
--- a/api/config.yml
+++ b/api/config.yml
@@ -8,6 +8,7 @@ meta:
# Liste aller möglichen Kollektionen (Listen, Seiten...) zum Projekt
collections:
- !include collections/general.yml
+ - !include collections/mediaLibrary.yml
- !include collections/articles.yml
- !include collections/content.yml
- !include collections/contact_form.yml
diff --git a/src/components/page/Article.svelte b/src/components/page/Article.svelte
new file mode 100644
index 0000000..ab31c88
--- /dev/null
+++ b/src/components/page/Article.svelte
@@ -0,0 +1,73 @@
+
+
+