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 @@ + + +
+ {#if article?.position !== "content"} +
+ {#if article?.title} +
{@html article?.title}
+ {/if} + {#if article?.position === "top" || article?.position === "end-of-content"} + {#if article?.subtitle} +
+ {@html article?.subtitle} +
+ {/if} + {/if} +
+ {/if} + + {#if article?.position !== "top"} +
+ {#if article?.position === "content"} + {#if article?.title} +
{@html article?.title}
+ {/if} + {/if} + {#if article?.position === "content" || article?.position === "top-of-content"} + {#if article?.subtitle} +
+ {@html article?.subtitle} +
+ {/if} + {/if} + + {#if !showDetails && article?.content} +
+ {@html article?.content} +
+ {/if} + + {#if showDetails && article?.details?.length} +
+ {@html article?.details} +
+ {/if} +
+ {/if} + + {#if !showDetails && article?.details} +
+ Details +
+ {/if} +
diff --git a/src/components/page/Galleries.svelte b/src/components/page/Galleries.svelte new file mode 100644 index 0000000..8fdf148 --- /dev/null +++ b/src/components/page/Galleries.svelte @@ -0,0 +1,114 @@ + + + + +
+ {#each galleries || [] as gallery} + + {/each} + + {#if selectedGallery && selectedImage} + + + + {/if} +
diff --git a/src/components/page/Modal.svelte b/src/components/page/Modal.svelte new file mode 100644 index 0000000..2b4f6dd --- /dev/null +++ b/src/components/page/Modal.svelte @@ -0,0 +1,35 @@ + + +