From 516c35dcb4b7d956316f4972cf9c98d07fbeae93 Mon Sep 17 00:00:00 2001 From: Mario Linz <mario@webmakers.de> Date: Wed, 25 May 2022 12:10:29 +0200 Subject: [PATCH] =?UTF-8?q?Weitere=20Verbesserungen=20des=20Starter=20Proj?= =?UTF-8?q?ekts=20f=C3=BCr=20neue=20Projekte.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/collections/content.yml | 13 +- api/collections/general.yml | 435 +++++++++--------- api/collections/navigation.yml | 1 + src/api.ts | 7 +- src/components/App.svelte | 34 +- src/components/routes/Content.svelte | 15 +- src/components/routes/Home.svelte | 39 +- .../widgets/GeneralMediaImage.svelte | 20 + src/components/widgets/LanguageChooser.svelte | 30 ++ src/components/widgets/Navigation.svelte | 9 +- src/components/widgets/ScrollTo.svelte | 8 +- src/css/theme-2022/components/general.less | 43 -- .../components/language-chooser.less | 22 + src/css/theme-2022/main.less | 1 + src/css/theme-2022/reset.less | 1 + src/store.ts | 19 +- types/global.d.ts | 2 +- 17 files changed, 398 insertions(+), 301 deletions(-) create mode 100644 src/components/widgets/GeneralMediaImage.svelte create mode 100644 src/components/widgets/LanguageChooser.svelte create mode 100644 src/css/theme-2022/components/language-chooser.less diff --git a/api/collections/content.yml b/api/collections/content.yml index 93a9aa7..3c04ea8 100644 --- a/api/collections/content.yml +++ b/api/collections/content.yml @@ -24,14 +24,18 @@ meta: mediaQuery: "(max-width:599px)" primaryText: path columns: - - name - - path + - source: path + twig: "{{locale}}{{path}}" + - source: locale + type: flag # Desktop - type: table mediaQuery: "(min-width:600px)" columns: - - name - - path + - source: path + twig: "{{locale}}{{path}}" + - source: locale + type: flag imageFilter: xs: @@ -102,6 +106,7 @@ hooks: # Feldliste der Kollektion fields: + - !include fields/_locale.yml - name: name type: string meta: diff --git a/api/collections/general.yml b/api/collections/general.yml index 47c8c9f..8373452 100644 --- a/api/collections/general.yml +++ b/api/collections/general.yml @@ -34,222 +34,225 @@ meta: - lastname - companyName - entryViewFields: - tabsSection: - meta: - expand: meta - tabs: - - name: general - meta: - label: { de: "Allgemein", en: "General" } - fields: - - name: public - type: boolean - meta: - defaultValue: true - label: - de: Veröffentlicht - en: Public - helperText: - de: "Alle allgemeinen Informationen werden auf der Seite angezeigt." - en: "All general information are displayed on the page." - - name: meta - meta: - label: { de: "Meta", en: "Meta" } - fields: - - name: meta - type: object - subFields: - - name: metaTitle - type: string - meta: - label: { de: "Titel der Webseite", en: "Page Title" } - - name: metaDescription - type: string - meta: - label: { de: "Beschreibung der Webseite", en: "Page Description" } - - name: metaTagRobots - type: string[] - meta: - widget: chipArray - label: - de: Robots - en: Robots - defaultValue: [] - autocomplete: true - choices: - - { id: "noindex", name: "noindex" } - - { id: "index", name: "index" } - - { id: "follow", name: "follow" } - - { id: "nofollow", name: "nofollow" } - - { id: "noimageindex", name: "noimageindex" } - - { id: "none", name: "none" } - - { id: "noarchive", name: "noarchive" } - - { id: "nocache", name: "nocache" } - - { id: "nosnippet", name: "nosnippet" } - - { id: "nnavailable_after", name: "nnavailable_after" } - helperText: - de: "<strong>Noindex</strong>: Weist eine Suchmaschine an, eine Seite nicht zu indizieren.<br/><strong>index</strong>: Weist eine Suchmaschine an, eine Seite zu indizieren. Beachten Sie, dass Sie dieses Meta-Tag nicht hinzufügen müssen; es ist die Voreinstellung.<br/><strong>follow</strong>: Auch wenn die Seite nicht indexiert ist, sollte der Crawler allen Links auf einer Seite folgen und Eigenkapital an die verlinkten Seiten weitergeben.<br/><strong>nofollow</strong>: Weist einen Crawler an, keinen Links auf einer Seite zu folgen oder Link-Equity weiterzugeben.<br/><strong>noimageindex</strong>: Weist einen Crawler an, keine Bilder auf einer Seite zu indizieren.<br/><strong>none</strong>: Entspricht der gleichzeitigen Verwendung der noindex- und nofollow-Tags.<br/><strong>noarchive</strong>: Suchmaschinen sollten keinen zwischengespeicherten Link zu dieser Seite auf einem SERP anzeigen.<br/><strong>nocache</strong>: Wie noarchive, aber nur von Internet Explorer und Firefox verwendet.<br/><strong>nosnippet</strong>: Weist eine Suchmaschine an, kein Snippet dieser Seite (d. h. Meta-Beschreibung) dieser Seite auf einem SERP anzuzeigen.<br/><strong>nnavailable_after</strong>: Suchmaschinen sollen diese Seite nach einem bestimmten Datum nicht mehr indexieren.<br/>" - en: "<strong>Noindex</strong>: Tells a search engine not to index a page.<br/><strong>index</strong>: Tells a search engine to index a page. Note that you don’t need to add this meta tag; it’s the default.<br/><strong>follow</strong>: Even if the page isn’t indexed, the crawler should follow all the links on a page and pass equity to the linked pages.<br/><strong>nofollow</strong>: Tells a crawler not to follow any links on a page or pass along any link equity.<br/><strong>noimageindex</strong>: Tells a crawler not to index any images on a page.<br/><strong>none</strong>: Equivalent to using both the noindex and nofollow tags simultaneously.<br/><strong>noarchive</strong>: Search engines should not show a cached link to this page on a SERP.<br/><strong>nocache</strong>: Same as noarchive, but only used by Internet Explorer and Firefox.<br/><strong>nosnippet</strong>: Tells a search engine not to show a snippet of this page (i.e. meta description) of this page on a SERP.<br/><strong>nnavailable_after</strong>: Search engines should no longer index this page after a particular date.<br/>" - - name: metaKeywords - type: string - meta: - label: { de: "SEO / Schlüsselwörter", en: "SEO / Keywords" } - helperText: - de: "Beispiel: Stichwort1, Stichwort2, Stichwort3" - en: "Example: keyword1, keyword2, keyword3" - - name: person - meta: - label: { de: "Person", en: "Person" } - fields: - - name: person - type: object - subFields: - - name: salutation - type: string - meta: - label: { de: "Anrede", en: "Salutation" } - - name: firstname - type: string - meta: - label: { de: "Vorname", en: "Firstname" } - - name: lastname - type: string - meta: - label: { de: "Nachname", en: "Lastname" } - - name: additional - type: string - meta: - label: { de: "Zusatz", en: "Additional" } - - name: street - type: string - meta: - label: { de: "Straße", en: "Street" } - - name: postcode - type: string - meta: - label: { de: "Postleitzahl", en: "Postcode" } - - name: city - type: string - meta: - label: { de: "Ort", en: "City" } - - name: tel - type: string - meta: - label: { de: "Telefonnummer", en: "Phone number" } - - name: fax - type: string - meta: - label: { de: "Faxnummer", en: "Fax number" } - - name: mobile - type: string - meta: - label: { de: "Handynummer", en: "Mobile number" } - - name: email - type: string - meta: - label: { de: "E-Mail", en: "E-Mail" } - - name: company - meta: - label: { de: "Unternehmen", en: "Company" } - fields: - - name: person - type: object - subFields: - - name: companyName - type: string - meta: - label: { de: "Name des Unternehmens", en: "Company Name" } - - name: companyWebUrl - type: string - meta: - label: { de: "URL zur Webseite", en: "Website URL" } - - name: companyAddresses - type: object[] - meta: - label: - de: Adresse - en: Adresse - css: - subFields: - - name: street - type: string - meta: - label: { de: "Straße", en: "Street" } - - name: houseNr - type: string - meta: - label: { de: "Hausnummer", en: "House number" } - - name: postcode - type: string - meta: - label: { de: "PLZ", en: "ZIP" } - - name: city - type: string - meta: - label: { de: "Ort", en: "City" } - - name: tel - type: string - meta: - label: { de: "Telefon", en: "Phone number" } - - name: fax - type: string - meta: - label: { de: "Fax", en: "Fax" } - - name: email - type: string - meta: - label: { de: "E-Mail", en: "E-Mail" } - - name: media - meta: - label: { de: "Medien", en: "Media" } - fields: - - name: media - type: object - subFields: - - name: favicon - type: file - meta: - label: { de: "Favicon", en: "Favicon" } - helperText: - de: "Ein Favicon ist ein kleines Icon, Symbol oder Logo, das von Webbrowsern verwendet wird, um eine Website auf wiedererkennbare Weise zu kennzeichnen." - en: "A favicon is a small icon, symbol, or logo used by web browsers to identify a website in a recognizable way." - - name: brand - type: file - meta: - label: { de: "Logo / Brand", en: "Logo / Brand" } - helperText: - de: "Logo der Seite" - en: "Page Logo" - - name: mediaFiles - type: object[] - meta: - label: { de: "Dateien", en: "Files" } - 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: - label: { de: "", en: "" } - - name: copyright - meta: - label: { de: "Copyright", en: "Copyright" } - fields: - - name: copyrightText - type: string - meta: - label: { de: "Copyright Text", en: "Copyright Text" } + tabsSection: + meta: + expand: media + tabs: + - name: general + meta: + label: { de: "Allgemein", en: "General" } + fields: + - name: public + type: boolean + meta: + defaultValue: true + label: + de: Veröffentlicht + en: Public + helperText: + de: "Alle allgemeinen Informationen werden auf der Seite angezeigt." + en: "All general information are displayed on the page." + - name: meta + meta: + label: { de: "Meta", en: "Meta" } + fields: + - name: meta + type: object + subFields: + - name: metaTitle + type: string + meta: + label: { de: "Titel der Webseite", en: "Page Title" } + - name: metaDescription + type: string + meta: + label: { de: "Beschreibung der Webseite", en: "Page Description" } + - name: metaTagRobots + type: string[] + meta: + widget: chipArray + label: + de: Robots + en: Robots + defaultValue: [] + autocomplete: true + choices: + - { id: "noindex", name: "noindex" } + - { id: "index", name: "index" } + - { id: "follow", name: "follow" } + - { id: "nofollow", name: "nofollow" } + - { id: "noimageindex", name: "noimageindex" } + - { id: "none", name: "none" } + - { id: "noarchive", name: "noarchive" } + - { id: "nocache", name: "nocache" } + - { id: "nosnippet", name: "nosnippet" } + - { id: "nnavailable_after", name: "nnavailable_after" } + helperText: + de: "<strong>Noindex</strong>: Weist eine Suchmaschine an, eine Seite nicht zu indizieren.<br/><strong>index</strong>: Weist eine Suchmaschine an, eine Seite zu indizieren. Beachten Sie, dass Sie dieses Meta-Tag nicht hinzufügen müssen; es ist die Voreinstellung.<br/><strong>follow</strong>: Auch wenn die Seite nicht indexiert ist, sollte der Crawler allen Links auf einer Seite folgen und Eigenkapital an die verlinkten Seiten weitergeben.<br/><strong>nofollow</strong>: Weist einen Crawler an, keinen Links auf einer Seite zu folgen oder Link-Equity weiterzugeben.<br/><strong>noimageindex</strong>: Weist einen Crawler an, keine Bilder auf einer Seite zu indizieren.<br/><strong>none</strong>: Entspricht der gleichzeitigen Verwendung der noindex- und nofollow-Tags.<br/><strong>noarchive</strong>: Suchmaschinen sollten keinen zwischengespeicherten Link zu dieser Seite auf einem SERP anzeigen.<br/><strong>nocache</strong>: Wie noarchive, aber nur von Internet Explorer und Firefox verwendet.<br/><strong>nosnippet</strong>: Weist eine Suchmaschine an, kein Snippet dieser Seite (d. h. Meta-Beschreibung) dieser Seite auf einem SERP anzuzeigen.<br/><strong>nnavailable_after</strong>: Suchmaschinen sollen diese Seite nach einem bestimmten Datum nicht mehr indexieren.<br/>" + en: "<strong>Noindex</strong>: Tells a search engine not to index a page.<br/><strong>index</strong>: Tells a search engine to index a page. Note that you don’t need to add this meta tag; it’s the default.<br/><strong>follow</strong>: Even if the page isn’t indexed, the crawler should follow all the links on a page and pass equity to the linked pages.<br/><strong>nofollow</strong>: Tells a crawler not to follow any links on a page or pass along any link equity.<br/><strong>noimageindex</strong>: Tells a crawler not to index any images on a page.<br/><strong>none</strong>: Equivalent to using both the noindex and nofollow tags simultaneously.<br/><strong>noarchive</strong>: Search engines should not show a cached link to this page on a SERP.<br/><strong>nocache</strong>: Same as noarchive, but only used by Internet Explorer and Firefox.<br/><strong>nosnippet</strong>: Tells a search engine not to show a snippet of this page (i.e. meta description) of this page on a SERP.<br/><strong>nnavailable_after</strong>: Search engines should no longer index this page after a particular date.<br/>" + - name: metaKeywords + type: string + meta: + label: { de: "SEO / Schlüsselwörter", en: "SEO / Keywords" } + helperText: + de: "Beispiel: Stichwort1, Stichwort2, Stichwort3" + en: "Example: keyword1, keyword2, keyword3" + - name: person + meta: + label: { de: "Person", en: "Person" } + fields: + - name: person + type: object + subFields: + - name: salutation + type: string + meta: + label: { de: "Anrede", en: "Salutation" } + - name: firstname + type: string + meta: + label: { de: "Vorname", en: "Firstname" } + - name: lastname + type: string + meta: + label: { de: "Nachname", en: "Lastname" } + - name: additional + type: string + meta: + label: { de: "Zusatz", en: "Additional" } + - name: street + type: string + meta: + label: { de: "Straße", en: "Street" } + - name: postcode + type: string + meta: + label: { de: "Postleitzahl", en: "Postcode" } + - name: city + type: string + meta: + label: { de: "Ort", en: "City" } + - name: tel + type: string + meta: + label: { de: "Telefonnummer", en: "Phone number" } + - name: fax + type: string + meta: + label: { de: "Faxnummer", en: "Fax number" } + - name: mobile + type: string + meta: + label: { de: "Handynummer", en: "Mobile number" } + - name: email + type: string + meta: + label: { de: "E-Mail", en: "E-Mail" } + - name: company + meta: + label: { de: "Unternehmen", en: "Company" } + fields: + - name: person + type: object + subFields: + - name: companyName + type: string + meta: + label: { de: "Name des Unternehmens", en: "Company Name" } + - name: companyWebUrl + type: string + meta: + label: { de: "URL zur Webseite", en: "Website URL" } + - name: companyAddresses + type: object[] + meta: + label: + de: Adresse + en: Adresse + css: + subFields: + - name: street + type: string + meta: + label: { de: "Straße", en: "Street" } + - name: houseNr + type: string + meta: + label: { de: "Hausnummer", en: "House number" } + - name: postcode + type: string + meta: + label: { de: "PLZ", en: "ZIP" } + - name: city + type: string + meta: + label: { de: "Ort", en: "City" } + - name: tel + type: string + meta: + label: { de: "Telefon", en: "Phone number" } + - name: fax + type: string + meta: + label: { de: "Fax", en: "Fax" } + - name: email + type: string + meta: + label: { de: "E-Mail", en: "E-Mail" } + - name: media + meta: + label: { de: "Medien", en: "Media" } + fields: + - name: media + type: object + subFields: + - name: favicon + type: file + meta: + label: { de: "Favicon", en: "Favicon" } + helperText: + de: "Ein Favicon ist ein kleines Icon, Symbol oder Logo, das von Webbrowsern verwendet wird, um eine Website auf wiedererkennbare Weise zu kennzeichnen." + en: "A favicon is a small icon, symbol, or logo used by web browsers to identify a website in a recognizable way." + - name: brand + type: file + meta: + label: { de: "Logo / Brand", en: "Logo / Brand" } + helperText: + de: "Logo der Seite" + en: "Page Logo" + - name: mediaFiles + type: object[] + meta: + label: { de: "Dateien", en: "Files" } + 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: + editableWhileCreating: true + label: { de: "Technischer Name / ID", en: "Technical name / ID" } + helperText: + de: "Achtung: Eine technische ID ist meist fest im Code der Seite verknüpft und darf, wenn sie einmal gesetzt wurde, nicht verändert werden!" + en: "Attention: A technical ID is usually permanently linked in the code of the page and, once it has been set, must not be changed!" + - name: file + type: file + meta: + label: { de: "Datei", en: "File" } + - name: copyright + meta: + label: { de: "Copyright", en: "Copyright" } + fields: + - name: copyrightText + type: string + meta: + label: { de: "Copyright Text", en: "Copyright Text" } imageFilter: xs: diff --git a/api/collections/navigation.yml b/api/collections/navigation.yml index bc69477..5b71f5b 100644 --- a/api/collections/navigation.yml +++ b/api/collections/navigation.yml @@ -204,3 +204,4 @@ indexes: key: - ident - locale + - path diff --git a/src/api.ts b/src/api.ts index 977ef7f..be4263a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -186,8 +186,11 @@ export const sendEmail = async (type: string = "contactForm", data: any, noToken }) } -export const getContent = async (path: string): Promise<Content> => { - const c = await api<Content[]>("content", { limit: 1, filter: { path } }) +export const getContent = async (path: string, lang: string): Promise<Content> => { + const c = await api<Content[]>("content", { + limit: 1, + filter: { path: path.replace("/" + lang, ""), locale: lang }, + }) if (c?.data?.length) { return c.data[0] } diff --git a/src/components/App.svelte b/src/components/App.svelte index e21e0fb..aa22c84 100644 --- a/src/components/App.svelte +++ b/src/components/App.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { Router, Route } from "svelte-routing" import { scrollToTop } from "svelte-scrollto" - import { location } from "../store" + import { generalInfo, location } from "../store" import Home from "./routes/Home.svelte" import Content from "./routes/Content.svelte" @@ -10,6 +10,7 @@ import Footer from "./widgets/Footer.svelte" export let url = "" + if (url) { // ssr let l = url.split("?") @@ -22,13 +23,40 @@ } // scroll to top on new site - location.subscribe((l) => { - if (l.push) scrollToTop() + location.subscribe((location) => { + if (location.push) scrollToTop() }) if (typeof window !== "undefined") console.log("App initialized") </script> +<svelte:head> + {#if $generalInfo?.meta?.metaTitle} + <title>{$generalInfo?.meta?.metaTitle}</title> + {/if} + {#if $generalInfo?.meta?.metaDescription} + <meta name="description" content="{$generalInfo?.meta?.metaDescription}" /> + {/if} + {#if $generalInfo?.meta?.metaKeywords} + <meta name="keywords" content="{$generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}" /> + {/if} + {#if $generalInfo?.person?.firstname || $generalInfo?.person?.lastname} + <meta + name="author" + content="{$generalInfo?.person?.firstname ? $generalInfo?.person?.firstname : ''} {$generalInfo?.person + ?.lastname + ? $generalInfo?.person?.lastname + : ''}" + /> + {/if} + {#if $generalInfo?.meta?.metaTagRobots} + <meta name="robots" content="{$generalInfo?.meta?.metaTagRobots}" /> + {/if} + {#if $generalInfo?.media?.favicon} + <link rel="shortcut icon" type="image/x-icon" href="{$generalInfo?.media?.favicon.src}" /> + {/if} +</svelte:head> + <Header /> <div> diff --git a/src/components/routes/Content.svelte b/src/components/routes/Content.svelte index e0645d9..62e2b0d 100644 --- a/src/components/routes/Content.svelte +++ b/src/components/routes/Content.svelte @@ -1,7 +1,6 @@ <script lang="ts"> import { getContent } from "../../api" - // import { apiBaseURL } from "../../config" - import { generalInfo } from "../../store" + import { generalInfo, currentLang } from "../../store" export let path: string @@ -10,7 +9,7 @@ function load() { loading = true - getContent(path) + getContent(path, $currentLang) .then((c) => { content = c }) @@ -24,10 +23,6 @@ <svelte:head> <title>{content?.name ? content?.name + " - " : ""}{$generalInfo?.meta?.metaTitle}</title> - <meta name="description" content="{$generalInfo?.meta?.metaDescription}" /> - <meta name="keywords" content="{$generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}" /> - <meta name="author" content="{$generalInfo?.person?.firstname} {$generalInfo?.person?.lastname}" /> - <meta name="robots" content="{$generalInfo?.meta?.metaTagRobots}" /> </svelte:head> <div class="container"> @@ -37,12 +32,8 @@ <!-- Loader --> {:else if content} {#each content.blocks || [] as b} - <h2>{b.title}</h2> - <div>{@html b.text}</div> + {JSON.stringify(b)} {/each} - {:else} - <h1>Seite nicht gefunden</h1> - <div>Pfad: {path}</div> {/if} </div> </div> diff --git a/src/components/routes/Home.svelte b/src/components/routes/Home.svelte index 162fda0..3cea647 100644 --- a/src/components/routes/Home.svelte +++ b/src/components/routes/Home.svelte @@ -6,20 +6,45 @@ import GoogleMaps from "../widgets/GoogleMaps.svelte" import ScrollTo from "../widgets/ScrollTo.svelte" import ContactForm from "../widgets/ContactForm.svelte" + import GeneralMediaImage from "../widgets/GeneralMediaImage.svelte" let expandedForm: string = "recipe" </script> -<svelte:head> - <title>{$generalInfo?.meta?.metaTitle}</title> - <meta name="description" content="{$generalInfo?.meta?.metaDescription}" /> - <meta name="keywords" content="{$generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}" /> - <meta name="author" content="{$generalInfo?.person?.firstname} {$generalInfo?.person?.lastname}" /> - <meta name="robots" content="{$generalInfo?.meta?.metaTagRobots}" /> -</svelte:head> +<!-- <svelte:head> + {#if $generalInfo?.meta?.metaTitle} + <title>{$generalInfo?.meta?.metaTitle}</title> + {/if} + {#if $generalInfo?.meta?.metaDescription} + <meta name="description" content="{$generalInfo?.meta?.metaDescription}" /> + {/if} + {#if $generalInfo?.meta?.metaKeywords} + <meta name="keywords" content="{$generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}" /> + {/if} + {#if $generalInfo?.person?.firstname || $generalInfo?.person?.lastname} + <meta + name="author" + content="{$generalInfo?.person?.firstname ? $generalInfo?.person?.firstname : ''} {$generalInfo?.person + ?.lastname + ? $generalInfo?.person?.lastname + : ''}" + /> + {/if} + {#if $generalInfo?.meta?.metaTagRobots} + <meta name="robots" content="{$generalInfo?.meta?.metaTagRobots}" /> + {/if} + {#if $generalInfo?.media?.favicon} + <link rel="shortcut icon" type="image/x-icon" href="{$generalInfo?.media?.favicon.src}" /> + {/if} +</svelte:head> --> <section class="contact"> <div class="container"> + <div class="row"> + <div class="col-md-12"> + <GeneralMediaImage id="test1" /> + </div> + </div> <div class="row nospace"> <div class="col-md-6"> <ContactForm type="recipe" collapsed="{expandedForm !== 'recipe'}" /> diff --git a/src/components/widgets/GeneralMediaImage.svelte b/src/components/widgets/GeneralMediaImage.svelte new file mode 100644 index 0000000..1516caa --- /dev/null +++ b/src/components/widgets/GeneralMediaImage.svelte @@ -0,0 +1,20 @@ +<script lang="ts"> + import { generalInfo } from "../../store" + + export let id: string = null + export let cssClass: string = "" +</script> + +{#if id} + {#each $generalInfo?.media?.mediaFiles || [] as mediaFile} + {#if mediaFile.id === id && mediaFile.file} + {#if mediaFile.file.src.includes(";base64,")} + <img + src="{mediaFile.file.src}" + alt="{mediaFile.alternateText ? mediaFile.alternateText + ' - ' : ''}" + class="{cssClass}" + /> + {/if} + {/if} + {/each} +{/if} diff --git a/src/components/widgets/LanguageChooser.svelte b/src/components/widgets/LanguageChooser.svelte new file mode 100644 index 0000000..33abfc4 --- /dev/null +++ b/src/components/widgets/LanguageChooser.svelte @@ -0,0 +1,30 @@ +<script lang="ts"> + import { navigations, location, currentLang } from "../../store" + + $: languages = [] + + $: if ($navigations?.length) { + $navigations.forEach((nav) => { + if (!languages.includes(nav.locale)) { + languages.push(nav.locale) + } + }) + languages = languages + } + + $: console.log($location) +</script> + +<div class="language-chooser"> + {#each languages as language} + <div + class="lang" + class:active="{$currentLang === language}" + on:click="{() => { + $currentLang = language + }}" + > + {language} + </div> + {/each} +</div> diff --git a/src/components/widgets/Navigation.svelte b/src/components/widgets/Navigation.svelte index 12d9366..dcc7e29 100644 --- a/src/components/widgets/Navigation.svelte +++ b/src/components/widgets/Navigation.svelte @@ -2,11 +2,12 @@ import * as animateScroll from "svelte-scrollto" import Icon from "mdi-svelte" import { mdiMenu } from "@mdi/js" - // import { generalInfo } from "../../store" import { links } from "svelte-routing" import { navigations } from "../../store" + import LanguageChooser from "./LanguageChooser.svelte" + export let ident = "main" let navigation: Navigation @@ -21,6 +22,8 @@ } </script> +<LanguageChooser /> + {#if navigation} <nav class="{ident}" use:links> {#each navigation?.items || [] as item} @@ -36,7 +39,7 @@ {item.settings.title} </a> {:else} - <a href="{item.settings.page}"> + <a href="/{navigation.locale}{item.settings.page}"> {item.settings.title} </a> {/if} @@ -67,7 +70,7 @@ </div> {:else} <div class="nav-item"> - <a href="{item.settings.page}" on:click="{() => (showMobileNav = false)}"> + <a href="/{navigation.locale}{item.settings.page}" on:click="{() => (showMobileNav = false)}"> {item.settings.title} </a> </div> diff --git a/src/components/widgets/ScrollTo.svelte b/src/components/widgets/ScrollTo.svelte index a73fd01..68b3068 100644 --- a/src/components/widgets/ScrollTo.svelte +++ b/src/components/widgets/ScrollTo.svelte @@ -1,6 +1,8 @@ <script lang="ts"> import { createEventDispatcher } from "svelte" + import GeneralMediaImage from "./GeneralMediaImage.svelte" + const dispatch = createEventDispatcher() </script> @@ -14,7 +16,7 @@ }) }}" > - <!-- <img src="img/icon/contact.svg" alt="" /> --> + <GeneralMediaImage id="contact" /> </a> </div> <div class="circle-contact"> @@ -26,12 +28,12 @@ }) }}" > - <!-- <img src="img/icon/recipe.svg" alt="" /> --> + <GeneralMediaImage id="recipe" /> </a> </div> <div class="circle-top"> <a href="/#"> - <!-- <img src="img/icon/chevron-up.svg" alt="" /> --> + <GeneralMediaImage id="up" /> </a> </div> </div> diff --git a/src/css/theme-2022/components/general.less b/src/css/theme-2022/components/general.less index c336783..0dd46c3 100755 --- a/src/css/theme-2022/components/general.less +++ b/src/css/theme-2022/components/general.less @@ -19,39 +19,6 @@ body { } } -// Body Images - -.body-image-left { - position: absolute; - left: 0; - top: 80rem; - - @media (max-width: 900px) { - top: 90rem; - } -} - -// Lists - -ul { - list-style-type: none; - padding-left: 15px; - - li { - line-height: 30px; - padding-left: 0; - font-weight: 700; - - &:before { - content: "\203A"; - font-weight: 700; - position: absolute; - top: -1px; - left: -12px; - } - } -} - // Scroll To Top .scroll-to-top { @@ -96,13 +63,3 @@ ul { right: -53px; } } - -// Promotion - -.promotion-image-wave-top { - height: 70px; -} - -.promotion-image-wave-bottom { - height: 137px; -} diff --git a/src/css/theme-2022/components/language-chooser.less b/src/css/theme-2022/components/language-chooser.less new file mode 100644 index 0000000..cfe3887 --- /dev/null +++ b/src/css/theme-2022/components/language-chooser.less @@ -0,0 +1,22 @@ +.language-chooser { + display: flex; + justify-content: flex-end; + align-items: center; + border: 1px solid #ccc; + + .lang { + border: 1px solid #ccc; + cursor: pointer; + + &:hover { + background: #ccc; + color: black; + } + + &.active { + background: #ccc; + color: black; + font-weight: 700; + } + } +} diff --git a/src/css/theme-2022/main.less b/src/css/theme-2022/main.less index e16e29b..8a809ca 100644 --- a/src/css/theme-2022/main.less +++ b/src/css/theme-2022/main.less @@ -53,5 +53,6 @@ @import "components/history"; @import "components/top-section"; @import "components/forms"; +@import "components/language-chooser"; @import "components/cc-bar"; diff --git a/src/css/theme-2022/reset.less b/src/css/theme-2022/reset.less index 23a118c..04458d0 100644 --- a/src/css/theme-2022/reset.less +++ b/src/css/theme-2022/reset.less @@ -49,6 +49,7 @@ a:not([class]) { /* Make images easier to work with */ img, picture { + width: 100%; max-width: 100%; display: block; } diff --git a/src/store.ts b/src/store.ts index 19880f5..75e3148 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,20 +1,25 @@ import { writable, get } from "svelte/store" import { getGeneralInformation, getArticles, getNavigations } from "./api" -const initLoc = { +// Localtion + +const initialLocation = { path: (typeof window !== "undefined" && window.location?.pathname) || "/", search: (typeof window !== "undefined" && window.location?.search) || "", push: false, pop: false, } +export const location = writable(initialLocation) -export const location = writable(initLoc) +// Current Language -const locale = { - key: "de", - title: "Deutsch", +function langFromUrl(): string { + if (new RegExp(`\/[a-zA-Z]*[-[a-zA-Z]*]{0,1}\/[a-zA-Z0-9-]*$`).test(get(location).path)) { + return get(location)?.path.split("/")[1] + } + return "de" } -export const currentLocale = writable(locale) +export const currentLang = writable<string>(langFromUrl()) // General Information @@ -43,7 +48,7 @@ const getAllNavigations = async (locale: Locale) => { const list = await getNavigations(locale) navigations.set(list) } -getAllNavigations(locale) +getAllNavigations({ key: get(currentLang) }) // Cookies - Webmakers Cookie Bar diff --git a/types/global.d.ts b/types/global.d.ts index e65939e..727d208 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -117,7 +117,7 @@ interface NavigationItem { interface Locale { key: string - title: string + title?: string } interface GeneralImage {