Update and rework project structure with new pagebuilder concept. (based on RK Architekten and SFU Politik configs and sources)

This commit is contained in:
2022-11-17 16:01:52 +00:00
parent 825dfc18f9
commit 30c05143fe
1421 changed files with 3875 additions and 4975 deletions

View File

@@ -175,7 +175,7 @@ export const api = async <T>(
}
export const sendEmail = async (type: string = "contactForm", data: any, noToken?: boolean) => {
await api("email?type=" + type, {
await api("contact_form?type=" + type, {
method: "post",
body: data,
noToken,
@@ -186,15 +186,15 @@ export const sendEmail = async (type: string = "contactForm", data: any, noToken
})
}
export const getContent = async (apiParams: APIParams): Promise<Content> => {
export const getContent = async (apiParams: APIParams): Promise<Content[]> => {
const c = await api<Content[]>("content", {
// limit: 1,
sort: "-priority",
// sort: "-priority",
...apiParams,
})
if (c?.data?.length) {
return c.data[0]
return c.data
}
return null
@@ -216,25 +216,6 @@ export const getGeneralInformation = async (): Promise<GeneralInfo[]> => {
}
}
export const getArticles = async (collectionName: string, apiParams: APIParams): Promise<TibiArticle[]> => {
try {
let apiParameters = {
method: "get",
offset: 0,
filter: {},
sort: "article.general.sort",
...apiParams,
}
apiParameters.filter["article.general.public"] = true
let response = await api<TibiArticle[]>(collectionName, apiParameters)
return response.data
} catch (e) {
console.error(e)
return null
}
}
export const getNavigations = async (l: Locale): Promise<Navigation[]> => {
try {
let response = await api<Navigation[]>("navigation", {
@@ -250,22 +231,22 @@ export const getNavigations = async (l: Locale): Promise<Navigation[]> => {
}
}
export const getGalleries = async (galIds: number[], params?: APIParams): Promise<Gallery[]> => {
try {
let response = await api<Gallery[]>("galleries", {
method: "get",
offset: 0,
params: {
sort: "title",
...params,
},
filter: {
_id: { $in: galIds },
},
})
// export const getGalleries = async (galIds: number[], params?: APIParams): Promise<Gallery[]> => {
// try {
// let response = await api<Gallery[]>("galleries", {
// method: "get",
// offset: 0,
// params: {
// sort: "title",
// ...params,
// },
// filter: {
// _id: { $in: galIds },
// },
// })
return response.data
} catch (e) {
return null
}
}
// return response.data
// } catch (e) {
// return null
// }
// }

View File

@@ -39,7 +39,7 @@
<meta name="description" content="{$generalInfo?.meta?.metaDescription}" />
{/if}
{#if $generalInfo?.meta?.metaKeywords}
<meta name="keywords" content="{$generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}" />
<meta name="keywords" content="{$generalInfo?.meta?.metaKeywords?.replaceAll(' ', '')}" />
{/if}
{#if $generalInfo?.person?.firstname || $generalInfo?.person?.lastname}
<meta

View File

@@ -0,0 +1,28 @@
<script lang="ts">
import modules from "./modules"
export let content: Content
</script>
{#if content?.pageBuilder && content?.pageBuilder?.length}
<div class="page-builder">
{#each content.pageBuilder as row}
<div class="page-builder-row">
{#each Object.entries(row.columns) as [index, column]}
{#if row.publish}
{#if column.module || (column.html && column.html !== "")}
<div class="{column.width !== '' ? `page-builder-col-${column.width}` : ''}">
{#if column.html}
{@html column.html}
{/if}
{#if column.module}
<svelte:component this="{modules[column.module]}" content="{content}" />
{/if}
</div>
{/if}
{/if}
{/each}
</div>
{/each}
</div>
{/if}

View File

@@ -0,0 +1,48 @@
<script lang="ts">
import { _ } from "svelte-i18n"
import { generalInfo } from "../../../store"
</script>
{#if $generalInfo && $generalInfo?.company?.companyAddresses}
<div class="addresses">
<div class="address-companyName">
<strong>{$generalInfo?.company?.companyName}</strong>
</div>
<div class="address-list">
{#each $generalInfo.company.companyAddresses as address}
<div class="address">
{#if address.street && address.houseNumber}
<div class="address-item street">
<span>{address.street}</span>
<span>{address.houseNumber}</span>
</div>
{/if}
{#if address.postcode && address.city}
<div class="address-item city">
<span>{address.postcode}</span>
<span>{address.city}</span>
</div>
{/if}
{#if address.tel}
<div class="address-item tel">
<span>{$_("tel")}</span>
<span>{address.tel}</span>
</div>
{/if}
{#if address.fax}
<div class="address-item fax">
<span>{$_("fax")}</span>
<span>{address.fax}</span>
</div>
{/if}
{#if address.email}
<div class="address-item email">
<span>{$_("email")}</span>
<a href="mailto:{address.email}">{address.email}</a>
</div>
{/if}
</div>
{/each}
</div>
</div>
{/if}

View File

@@ -0,0 +1,148 @@
<script lang="ts">
import { _ } from "svelte-i18n"
import { fade } from "svelte/transition"
import { mdiCheck } from "@mdi/js"
import Icon from "mdi-svelte"
import { link } from "svelte-routing"
import { sendEmail } from "../../../api"
import { currentLang } from "../../../store"
export let type: string = "contact"
let formData: {
name: string
email: string
subject: string
message: string
privacy: boolean
} = {
name: null,
email: null,
subject: null,
message: null,
privacy: false,
}
let requestSucessfully: boolean = false
let requestPending: boolean = false
const submit = () => {
if (
formData["name"] &&
formData["email"] &&
formData["subject"] &&
formData["message"] &&
formData["privacy"]
) {
requestPending = true
sendEmail(type + "Form", formData)
.then(() => {
resetForm()
requestSucessfully = true
requestPending = false
setTimeout(() => {
requestSucessfully = false
}, 10000)
})
.catch((e) => {
console.error(e)
requestPending = false
})
.finally(() => {
requestPending = false
})
}
}
const resetForm = () => {
formData = {
name: null,
email: null,
subject: null,
message: null,
privacy: false,
}
}
$: isValid =
formData["name"] && formData["email"] && formData["subject"] && formData["message"] && formData["privacy"]
</script>
<form on:submit|preventDefault="{submit}">
<div class="row">
<div class="col-md-6 mt-sm">
<input
type="text"
bind:value="{formData['name']}"
placeholder="{$_('form.contact.name')}"
readonly="{requestPending}"
/>
</div>
<div class="col-md-6 mt-sm">
<input
type="email"
bind:value="{formData['email']}"
placeholder="{$_('form.contact.email')}"
readonly="{requestPending}"
/>
</div>
</div>
<div class="row">
<div class="col-md-12 mt-sm">
<input
type="text"
bind:value="{formData['subject']}"
placeholder="{$_('form.contact.subject')}"
readonly="{requestPending}"
/>
</div>
</div>
<div class="row">
<div class="col-md-12 mt-sm">
<textarea
bind:value="{formData['message']}"
readonly="{requestPending}"
placeholder="{$_('form.contact.message')}"></textarea>
</div>
</div>
<div class="row">
<div class="col-md-6 mt-sm">
<label for="privacy-checkbox" class="checkbox-container">
<div
class="checkbox"
id="privacy-checkbox"
on:click="{() => (formData.privacy = !formData.privacy)}"
on:keydown
>
{#if formData.privacy}
<div class="icon">
<Icon path="{mdiCheck}" size="2" />
</div>
{/if}
</div>
<div on:click|stopPropagation="{() => (formData.privacy = !formData.privacy)}" on:keydown>
<a use:link href="{`/${$currentLang}/${$_('privacy').toLowerCase()}`}" on:click|stopPropagation
><strong>{$_("privacy")}</strong></a
>
{$_("accept")}
</div>
</label>
</div>
<div class="col-md-6 mt-sm">
<button type="submit" disabled="{!isValid || requestPending}">{$_("form.contact.send")}</button>
</div>
</div>
{#if requestSucessfully}
<div class="mt-sm" transition:fade>
<div>
<strong>{$_("form.contact.thankYou")}</strong>
</div>
<p>{$_("form.contact.getInTouch")}</p>
</div>
{/if}
</form>

View File

@@ -0,0 +1,7 @@
import ContactForm from "./ContactForm.svelte"
import Addresses from "./Addresses.svelte"
export default {
ContactForm,
Addresses,
}

View File

@@ -4,7 +4,7 @@
import { getGalleries } from "../../api"
import { apiBaseURL } from "../../config"
import Modal from "./Modal.svelte"
import Modal from "../__UNUSED__/widgets/Modal.svelte"
export let article
let galleries: Gallery[]

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { generalInfo, ccTags } from "../../store"
import { generalInfo, ccTags } from "../../../store"
$: iframeTitle =
$generalInfo?.person?.salutation +

View File

@@ -1,192 +1,56 @@
<script lang="ts">
import { afterUpdate } from "svelte"
import * as animateScroll from "svelte-scrollto"
import { _ } from "svelte-i18n"
import { getContent, getArticles } from "../../api"
import { generalInfo, currentLang, location } from "../../store"
import { navigate } from "svelte-routing"
import { _, locale } from "svelte-i18n"
import { getContent } from "../../api"
import { generalInfo, currentLang } from "../../store"
import ArticlesList from "../widgets/ArticlesList.svelte"
import ArticleDetails from "../routes/ArticleDetails.svelte"
import Page from "./Page.svelte"
export let path: string
let pathLang: string
let loading = true
let content: Content
let article: TibiArticle
let connectedContentNotFound: boolean = false
let currentLocale: string = null
let blockedDoubleCall: boolean = false
$: currentDomain = window.location.origin
const loadContent = (type?: string) => {
// Set default API call filter
let filter: { [key: string]: any } = {
locale: $currentLang,
path,
const updateLang = () => {
if (pathLang !== $currentLang) {
let pathElements = path.split("/")
// Update currentLang in store
$currentLang = pathElements[0]
// Update i18n language
locale.set($currentLang)
}
}
// API call filter without locale if URL changed
if (path !== content?.path) {
delete filter.locale
}
// Changed filter to find simmilar content for changed language
if (type === "changedLanguage" && content?.pages) {
filter = {
_id: { $in: content?.pages },
const loadContent = async (path: string) => {
let apiParams: APIParams = {
filter: {
public: true,
locale: $currentLang,
}
delete filter.path
}
// Get content by API call
let apiParams: APIParams = {
filter,
path,
},
}
loading = true
getContent(apiParams)
.then((c) => {
if (c) {
if (type === "changedLanguage" && path !== c.path) {
let newPath = c.path + $location.search
window.history.pushState({}, document.getElementsByTagName("title")[0].innerHTML, newPath + "/")
blockedDoubleCall = true
path = newPath
}
content = c
connectedContentNotFound = false
} else {
// Show message if not found simmilar content for changed language
if (filter.tags) {
connectedContentNotFound = true
}
content = null
}
// Redirect to HOME if no content has been found. So the page 404 content will never shown.
if (!content) {
navigate("/")
}
})
.finally(() => {
loading = false
scrollToAnchor()
})
}
const loadArticle = (type?: string, locale: string = null) => {
let pathParts = path.split("/")
let slugOrId = pathParts[pathParts.length - 1].toString()
let urlLocale = pathParts[0].toString()
let loc = $currentLang
if (urlLocale) {
locale = urlLocale
}
// Set default API call filter
let filter: { [key: string]: any } = {
"article.general.locale": loc,
"article.content.slug": slugOrId,
}
// Changed filter to find simmilar article for changed language
if (type === "changedLanguage") {
filter = {
_id: { $in: article?.article?.assignments?.articles },
"article.general.locale": $currentLang,
}
}
// Get content by API call
let apiParams: APIParams = {
filter,
}
loading = true
getArticles("articles", apiParams)
.then((respoonse) => {
if (respoonse) {
if (type === "changedLanguage") {
let newPath =
"/" +
respoonse[0].article.assignments.pages +
"/" +
respoonse[0].article.content.slug +
$location.search
window.history.pushState({}, document.getElementsByTagName("title")[0].innerHTML, newPath)
}
article = respoonse[0]
} else {
article = null
// Redirect to HOME if no content has been found. So the page 404 content will never shown.
if (!content) {
navigate("/")
}
}
})
.finally(() => {
loading = false
scrollToAnchor()
})
}
currentLang.subscribe((locale) => {
currentLocale = locale
if (content) {
loadContent("changedLanguage")
} else if (article) {
loadArticle("changedLanguage", currentLocale)
} else if (window.location.pathname.endsWith("/")) {
loadContent()
const c = await getContent(apiParams)
if (c) {
content = c[0]
} else {
loadArticle(currentLocale)
window.history.back()
}
})
loading = false
}
$: if (path) {
// Set initial current locale for this page
if (!currentLocale) {
currentLocale = $currentLang
}
if (!blockedDoubleCall) {
// Reset all content and articles
content = null
article = null
// Update current language when lang in URL not equal to current language
if (path !== window.location.pathname) {
let pathParts = window.location.pathname.split("/")
if (pathParts.length > 3 && $currentLang !== pathParts[1]) {
$currentLang = currentLocale
}
}
}
blockedDoubleCall = false
updateLang()
loadContent(path)
}
afterUpdate(() => {
scrollToAnchor()
})
const scrollToAnchor = () => {
if (content && window.location.hash) {
window.setTimeout(() => {
animateScroll.scrollTo({
delay: 100,
element: window.location.hash,
offset: -200,
onDone: () => {},
})
}, 500)
}
}
$: console.log(content)
</script>
<svelte:head>
@@ -204,8 +68,8 @@
<meta
name="keywords"
content="{content?.meta?.metaKeywords
? content?.meta?.metaKeywords.replaceAll(' ', '')
: $generalInfo?.meta?.metaKeywords.replaceAll(' ', '')}"
? content?.meta?.metaKeywords?.replaceAll(' ', '')
: $generalInfo?.meta?.metaKeywords?.replaceAll(' ', '')}"
/>
<meta
name="robots"
@@ -224,22 +88,13 @@
{#if loading}
<!-- Loader -->
{:else if article}
<ArticleDetails entry="{article}" />
{:else if content}
<ArticlesList path="{path}" tags="{content?.tags}" />
<!-- Content Page Router -->
{#if content.type.includes("page")}
<Page content="{content}" />
{/if}
{:else}
<!-- <div class="page-404">
<div>
<Image
collectionName="general"
entryId="{$generalInfo.id}"
file="{$generalInfo?.media?.brand}"
alt="{$generalInfo?.meta?.metaTitle}"
cssClass="brand"
/>
</div>
<div class="page-404">
<h1>{$_("pageNotFound")}</h1>
<p class="mb-md">
@@ -266,5 +121,5 @@
},
})}
</p>
</div> -->
</div>
{/if}

View File

@@ -1,18 +1,38 @@
<script lang="ts">
import * as animateScroll from "svelte-scrollto"
// import { _ } from "svelte-i18n"
import { currentLang } from "../../store"
import { getContent } from "../../api"
// import { generalInfo } from "../../store"
let loading = true
let projects: Content[]
let currentImpressionsProject: Content
// import ContactForm from "../widgets/ContactForm.svelte"
// import GoogleMaps from "../widgets/GoogleMaps.svelte"
// import GeneralMediaImage from "../widgets/GeneralMediaImage.svelte"
import ArticlesList from "../widgets/ArticlesList.svelte"
const loadContent = async () => {
let apiParams: APIParams = {
filter: {
public: true,
locale: $currentLang,
type: "project",
},
}
loading = true
const c = await getContent(apiParams)
if (c) {
projects = c
currentImpressionsProject = projects[Math.floor(Math.random() * projects.length)]
}
loading = false
}
loadContent()
$: console.log(projects)
</script>
<ArticlesList pages="{['/']}" />
<!-- <GeneralMediaImage id="test1" /> -->
<!-- <ContactForm type="recipe" collapsed="{expandedForm !== 'recipe'}" /> -->
<!-- <ContactForm type="contact" collapsed="{expandedForm !== 'contact'}" /> -->
<!-- <GoogleMaps /> -->
{#if projects}
<section>
{JSON.stringify(projects)}
</section>
{/if}

View File

@@ -0,0 +1,11 @@
<script lang="ts">
import PageBuilder from "../PageBuilder/PageBuilder.svelte"
export let content: Content
</script>
{#if content}
<main class="page {content.type.join(' ').toLowerCase()}">
<PageBuilder content="{content}" />
</main>
{/if}

View File

@@ -1,227 +0,0 @@
<script lang="ts">
import { _ } from "svelte-i18n"
import { navigate, link } from "svelte-routing"
import TibiArticleMediaFile from "./TibiArticleMediaFile.svelte"
export let entry: CollectionEntry = null
export let cssClass: string = ""
export let showDetails: boolean = false
let path = window.location.pathname
let article = null
if (entry) {
article = entry.article
}
let marginClasses: string = ""
let paddingClasses: string = ""
let published: boolean = true
const updatePublishedState = () => {
let currentDate = new Date().getTime()
let from = new Date(article?.general?.publish_date?.from).getTime()
let until = new Date(article?.general?.publish_date?.until).getTime()
let publish = true
if (from && until) {
if (currentDate > from && currentDate < until) {
publish = true
} else {
publish = false
}
} else {
if (from) {
if (currentDate > from) {
publish = true
} else {
publish = false
}
}
if (until && publish) {
if (currentDate < until) {
publish = true
} else {
publish = false
}
}
}
published = publish
}
$: if (article) {
marginClasses = Object.values(article?.layout?.properties?.margin).join(" ").replace(" ", " ")
paddingClasses = Object.values(article?.layout?.properties?.padding).join(" ").replace(" ", " ")
}
$: if (article?.general?.publish_date?.from || article?.general?.publish_date?.until) updatePublishedState()
// Update publish state every interval time (default 60sec)
setInterval(
updatePublishedState,
article?.general?.publish_date?.interval ? article?.general?.publish_date?.interval : 60000
)
</script>
{#if article && published}
<article
class="{cssClass} {article?.layout?.variant} {marginClasses} {paddingClasses}"
id="{article?.content?.slug}"
>
{#if article?.layout?.variant === "top"}
{#if article?.content?.types?.media?.files?.length}
<TibiArticleMediaFile
collectionName="articles"
entryId="{entry.id}"
mediaFile="{article?.content?.types?.media?.files[0]}"
/>
{/if}
{#if article?.content?.title}
<div class="article-title">{@html article?.content?.title}</div>
{/if}
{#if article?.content?.subtitle}
<div class="article-subtitle">{@html article?.content?.subtitle}</div>
{/if}
{#if article?.content?.types?.teaser}
<div class="article-teaser">{@html article?.content?.types?.teaser}</div>
{/if}
{#if article?.link?.url}
<a
href="{article?.link?.url}"
target="{article?.link?.target ? article?.link?.target : '_self'}"
class="article-link">{@html article?.link?.text ? article?.link?.text : $_("details")}</a
>
{/if}
{#if article?.content?.types?.details && showDetails}
<div class="article-details">{@html article?.content?.types?.details}</div>
{/if}
{:else if article?.layout?.variant === "right"}
<div class="row">
<div class="col-md-8">
{#if article?.content?.title}
<div class="article-title">{@html article?.content?.title}</div>
{/if}
{#if article?.content?.subtitle}
<div class="article-subtitle">{@html article?.content?.subtitle}</div>
{/if}
{#if article?.content?.types?.teaser}
<div class="article-teaser">{@html article?.content?.types?.teaser}</div>
{/if}
{#if article?.link?.url}
<a
href="{article?.link?.url}"
target="{article?.link?.target ? article?.link?.target : '_self'}"
class="article-link">{@html article?.link?.text ? article?.link?.text : $_("details")}</a
>
{/if}
{#if article?.content?.types?.details && showDetails}
<div class="article-details">{@html article?.content?.types?.details}</div>
{/if}
</div>
<div class="col-md-4">
{#if article?.content?.types?.media?.files?.length}
<TibiArticleMediaFile
collectionName="articles"
entryId="{entry.id}"
mediaFile="{article?.content?.types?.media?.files[0]}"
/>
{/if}
</div>
</div>
{:else if article?.layout?.variant === "bottom"}
{#if article?.content?.title}
<div class="article-title">{@html article?.content?.title}</div>
{/if}
{#if article?.content?.subtitle}
<div class="article-subtitle">{@html article?.content?.subtitle}</div>
{/if}
{#if article?.content?.types?.teaser}
<div class="article-teaser">{@html article?.content?.types?.teaser}</div>
{/if}
{#if article?.link?.url}
<a
href="{article?.link?.url}"
target="{article?.link?.target ? article?.link?.target : '_self'}"
class="article-link">{@html article?.link?.text ? article?.link?.text : $_("details")}</a
>
{/if}
{#if article?.content?.types?.details && showDetails}
<div class="article-details">{@html article?.content?.types?.details}</div>
{/if}
{#if article?.content?.types?.media?.files?.length}
<TibiArticleMediaFile
collectionName="articles"
entryId="{entry.id}"
mediaFile="{article?.content?.types?.media?.files[0]}"
/>
{/if}
{:else if article?.layout?.variant === "left" || article?.layout?.variant === "default"}
<div class="row">
<div class="col-md-4">
{#if article?.content?.types?.media?.files?.length}
<TibiArticleMediaFile
collectionName="articles"
entryId="{entry.id}"
mediaFile="{article?.content?.types?.media?.files[0]}"
/>
{/if}
</div>
<div class="col-md-8">
{#if article?.content?.title}
<div class="article-title">{@html article?.content?.title}</div>
{/if}
{#if article?.content?.subtitle}
<div class="article-subtitle">{@html article?.content?.subtitle}</div>
{/if}
{#if article?.content?.types?.teaser}
<div class="article-teaser">{@html article?.content?.types?.teaser}</div>
{/if}
{#if article?.link?.url}
<a
href="{article?.link?.url}"
target="{article?.link?.target ? article?.link?.target : '_self'}"
class="article-link">{@html article?.link?.text ? article?.link?.text : $_("details")}</a
>
{/if}
{#if article?.content?.types?.details && showDetails}
<div class="article-details">{@html article?.content?.types?.details}</div>
{:else if article?.content?.types?.details}
<a
use:link
href="{`${path}${encodeURIComponent(
article?.content?.slug
? article?.content?.slug
.toLowerCase()
.replace(/[^a-zA-Z0-9]/g, '-')
.replaceAll('---', '--')
: entry.id
)}`}"
class="article-link"
>
{@html article?.link?.text ? article?.link?.text : $_("details")}
</a>
{/if}
</div>
</div>
{/if}
</article>
{/if}

View File

@@ -1,38 +0,0 @@
<script lang="ts">
import { currentLang } from "../../store"
import { getArticles } from "../../api"
import Article from "../widgets/Article.svelte"
export let tags: string[] = null
export let pages: string[] = null
export let path: string = null
let articleEntries: CollectionEntry[] = []
$: if ($currentLang) {
let filter = {
"article.general.locale": $currentLang,
}
if (tags && tags?.length) {
filter["article.assignments.tags"] = { $in: tags }
}
if (pages && pages?.length) {
filter["article.assignments.pages"] = { $in: pages }
}
if (path) {
filter["article.assignments.pages"] = { $in: [path] }
}
getArticles("articles", { filter }).then((response) => {
articleEntries = response
})
}
</script>
{#each articleEntries || [] as entry}
<Article entry="{entry}" />
{/each}

View File

@@ -1,160 +0,0 @@
<script lang="ts">
import { fade } from "svelte/transition"
import { mdiCheck, mdiChevronDown } from "@mdi/js"
import Icon from "mdi-svelte"
import { sendEmail } from "../../api"
export let type: string
export let collapsed: boolean = false
let formData: {
name: string
email: string
subject: string
message: string
privacy: boolean
} = {
name: null,
email: null,
subject: null,
message: null,
privacy: false,
}
let requestSucessfully: boolean = false
let requestPending: boolean = false
const submit = () => {
if (
formData["name"] &&
formData["email"] &&
formData["subject"] &&
formData["message"] &&
formData["privacy"]
) {
requestPending = true
sendEmail(type + "Form", formData)
.then(() => {
resetForm()
requestSucessfully = true
requestPending = false
setTimeout(() => {
requestSucessfully = false
}, 10000)
})
.catch((e) => {
console.error(e)
requestPending = false
})
.finally(() => {
requestPending = false
})
}
}
const resetForm = () => {
formData = {
name: null,
email: null,
subject: null,
message: null,
privacy: false,
}
}
$: isValid =
formData["name"] && formData["email"] && formData["subject"] && formData["message"] && formData["privacy"]
</script>
<div id="{type}">
<form on:submit|preventDefault="{submit}" class="mt-lg">
<div class="layout justify-content-space-between layout-gap-md">
<div class="hidden-sm icon {type}">
<!-- <img src="img/icon/{type}.svg" alt="" /> -->
</div>
<div class="titles" on:click="{() => (collapsed = !collapsed)}">
<h3 class="title">
{type === "contact" ? "Kontakt" : ""}
{type === "recipe" ? "Rezeptanfrage" : ""}
</h3>
<h4 class="subTitle">
{type === "contact" ? "Schreiben Sie uns Ihr Anliegen" : ""}
{type === "recipe" ? "Teilen Sie uns Ihren Rezeptwunsch mit" : ""}
</h4>
</div>
<div class="collapse-icon" class:collapsed="{!collapsed}" on:click="{() => (collapsed = !collapsed)}">
<Icon path="{mdiChevronDown}" size="2" />
</div>
</div>
{#if !collapsed}
<div>
<div class="row">
<div class="col-md-6 mt-sm">
<input
type="text"
bind:value="{formData['name']}"
placeholder="Name"
readonly="{requestPending}"
/>
</div>
<div class="col-md-6 mt-sm">
<input
type="text"
bind:value="{formData['email']}"
placeholder="E-Mail Adresse"
readonly="{requestPending}"
/>
</div>
</div>
<div class="row nospace">
<div class="col-md-12 mt-sm">
<input
type="text"
bind:value="{formData['subject']}"
placeholder="Betreff"
readonly="{requestPending}"
/>
</div>
</div>
<div class="row nospace">
<div class="col-md-12 mt-sm">
<textarea bind:value="{formData['message']}" readonly="{requestPending}"></textarea>
</div>
</div>
<div class="row nospace">
<div class="col-md-12 mt-sm">
<div class="layout layout-gap-md align-items-center">
<div
class="checkbox"
on:click="{() => {
formData.privacy = !formData.privacy
}}"
>
{#if formData.privacy}
<div class="icon">
<Icon path="{mdiCheck}" size="2" />
</div>
{/if}
</div>
<div on:click="{() => (formData.privacy = !formData.privacy)}">
<a href="/datenschutz"><strong>Datenschutz</strong></a> akzeptieren
</div>
</div>
</div>
</div>
{#if requestSucessfully}
<div class="mt-sm" transition:fade>
<div>
<strong>Vielen Dank für Ihre Kontaktaufnahme!</strong>
</div>
<p>Wir werden uns zeitnah mit Ihnen in Verbindung setzen!</p>
</div>
{/if}
<div class="layout justify-content-end mt-sm">
<button type="submit" disabled="{!isValid || requestPending}">Absenden</button>
</div>
</div>
{/if}
</form>
</div>

View File

@@ -5,20 +5,18 @@
</script>
<footer>
<div class="container">
<section class="no-space align-right">
<main class="section-content">
<Navigation ident="footer" />
</main>
</section>
{#if $generalInfo?.copyrightText}
<div class="row">
<div class="col-md-12">
<Navigation ident="footer" />
</div>
</div>
{#if $generalInfo?.copyrightText}
<div class="row">
<div class="col-md-12">
<div class="copyright">
{$generalInfo?.copyrightText}
</div>
<div class="copyright">
{$generalInfo?.copyrightText}
</div>
</div>
{/if}
</div>
</div>
{/if}
</footer>

View File

@@ -1,32 +1,45 @@
<script lang="ts">
import { link } from "svelte-routing"
// import * as animateScroll from "svelte-scrollto"
import { generalInfo } from "../../store"
import { generalInfo, showMobileNav } from "../../store"
import Navigation from "./Navigation.svelte"
import Image from "./Image.svelte"
let y: number = 0
let innerHeight: number = 0
let outerHeight: number = 0
</script>
<header>
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="header-content">
<a href="/" use:link>
<Image
collectionName="general"
entryId="{$generalInfo?.id}"
file="{$generalInfo?.media?.brand}"
alt="{$generalInfo?.meta?.metaTitle}"
cssClass="brand"
/>
</a>
<svelte:window bind:scrollY="{y}" bind:innerHeight bind:outerHeight />
<div class="header-content-right">
<Navigation />
</div>
</div>
<header>
<div class="header-content">
<a href="/" class="brand-container" use:link>
<Image
collectionName="general"
entryId="{$generalInfo?.id}"
file="{$generalInfo?.media?.brand}"
alt="{$generalInfo?.meta?.metaTitle}"
cssClass="brand"
/>
</a>
<div class="header-content-right">
<Navigation />
<div class="nav-mobile-toggle" on:click="{() => ($showMobileNav = !$showMobileNav)}" on:keydown>
{#if $showMobileNav}
<img src="img/icons/close.svg" alt="" />
{:else}
<img src="img/icons/menu.svg" alt="" />
{/if}
</div>
</div>
</div>
</header>
<div class="main-mobile" class:show="{$showMobileNav}">
<Navigation mobile="{true}" />
</div>

View File

@@ -1,16 +1,12 @@
<script lang="ts">
import Icon from "mdi-svelte"
import { mdiMenu } from "@mdi/js"
import { navigations, currentLang } from "../../store"
import LanguageChooser from "./LanguageChooser.svelte"
// import LanguageChooser from "./LanguageChooser.svelte"
import NavigationItem from "./NavigationItem.svelte"
export let ident = "main"
export let mobile: boolean = false
let navigation: Navigation
let showMobileNav: boolean = false
$: {
navigation = null
@@ -22,24 +18,12 @@
}
</script>
<LanguageChooser />
<!--<LanguageChooser />-->
{#if navigation}
<nav class="{ident}">
<nav class="{ident}" class:mobile>
{#each navigation?.items || [] as item}
<NavigationItem item="{item}" />
{/each}
</nav>
{#if ident === "main"}
<div class="nav-mobile-toggle" on:click="{() => (showMobileNav = !showMobileNav)}">
<Icon path="{mdiMenu}" size="2" />
</div>
<nav class="{ident}-mobile" class:show="{showMobileNav}">
{#each navigation?.items || [] as item}
<NavigationItem item="{item}" />
{/each}
</nav>
{/if}
{/if}

View File

@@ -1,32 +1,31 @@
<script lang="ts">
// import * as animateScroll from "svelte-scrollto"
import { link, navigate } from "svelte-routing"
import { location } from "../../store"
import { navigate } from "svelte-routing"
import { location, showMobileNav } from "../../store"
export let item: NavigationItem
const isActive = (itemPath: string, locationPath: string): boolean | any => {
itemPath = "/" + itemPath + (locationPath.endsWith("/") ? "/" : "")
locationPath = (locationPath.startsWith("/") ? "" : "/") + locationPath
itemPath = itemPath
locationPath = locationPath
if (!locationPath.endsWith("/")) {
return locationPath.startsWith(itemPath)
}
return itemPath === locationPath
return locationPath.includes(itemPath)
}
const onClickInternalLink = (item: NavigationItem) => {
let url = ""
if (item.settings?.page) {
url += item.settings?.page
}
if (item.settings?.url?.url) {
url += (url.endsWith("/") ? "" : "/") + item.settings.url.url
}
if (item.settings?.page) {
navigate(url, { replace: true })
$showMobileNav = false
navigate(url)
}
}
@@ -35,7 +34,7 @@
return item.settings.page
}
return item.settings.page + "/"
return item.settings.page
}
</script>
@@ -43,21 +42,29 @@
{#if item.settings.url.url}
{#if item.settings.url.target === "default"}
<a
use:link
on:click|preventDefault="{() => onClickInternalLink(item)}"
on:keydown
href="{getInternalUrl(item)}"
class:active="{isActive(item.settings.page, $location.path)}"
on:click|stopPropagation="{() => onClickInternalLink(item)}"
>
{item.settings.title}
<div class="box"></div>
<span>{item.settings.title}</span>
</a>
{:else}
<a href="{item.settings.url.url}" target="{item.settings.url.target}">
{item.settings.title}
<div class="box"></div>
<span>{item.settings.title}</span>
</a>
{/if}
{:else}
<a use:link href="{getInternalUrl(item)}" class:active="{isActive(item.settings.page, $location.path)}">
{item.settings.title}
<a
on:click|preventDefault="{() => onClickInternalLink(item)}"
on:keydown
href="{getInternalUrl(item)}"
class:active="{isActive(item.settings.page, $location.path)}"
>
<div class="box"></div>
<span>{item.settings.title}</span>
</a>
{/if}
{/if}

View File

@@ -1,56 +0,0 @@
<script lang="ts">
import { news } from "../../store"
const getNewsDate = (news) => {
const from = news?.from ? new Date(news?.from) : null
const until = news?.until ? new Date(news?.until) : null
const options = { year: "numeric", month: "2-digit", day: "2-digit" }
let d = ""
if (from) {
// @ts-ignore
d += from.toLocaleDateString("de-DE", options)
}
if (until) {
// @ts-ignore
d += " bis " + until.toLocaleDateString("de-DE", options)
}
if (news.title) {
d += " - "
}
return d
}
</script>
{#if $news?.length}
<section class="news" id="news">
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Neuigkeiten</h2>
</div>
</div>
<div class="row">
{#each $news as n}
{#if n.title || n.from || n.until}
<div class="col-md-6">
<article>
<div class="title">
{getNewsDate(n)}
{#if n.title}
{@html n.title}
{/if}
</div>
{#if n.content}
<div class="content">
{@html n.content}
</div>
{/if}
</article>
</div>
{/if}
{/each}
</div>
</div>
</section>
{/if}

View File

@@ -1,74 +0,0 @@
<svg
class="promotion-image-wave-top"
width="1920"
height="70"
viewBox="0 0 1920 70"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="m1920 70-80-12c-80-12-240-36-400-42s-320 6-480 18-320 24-480 18S160 22 80 10L0-2v-108h1920V70z"
fill="#fff"></path>
</svg>
<!-- <img src="img/promotion/promotion-image.png" alt="" class="promotion-image" /> -->
<svg class="promotion-image-wave-bottom" viewBox="0 0 1920 137" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 30.708 80 24.7c80-6.008 240-18.024 400-6.008 160 12.016 320 48.065 480 42.057 160-6.009 320-54.073 480-60.082 160-6.008 320 30.041 400 48.065l80 18.025V137H0V30.708z"
fill="url(#plkj8d2oga)"></path>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 30.708 80 24.7c80-6.008 240-18.024 400-6.008 160 12.016 320 48.065 480 42.057 160-6.009 320-54.073 480-60.082 160-6.008 320 30.041 400 48.065l80 18.025V137H0V30.708z"
fill="url(#iwnto70uxb)"></path>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 30.708 80 24.7c80-6.008 240-18.024 400-6.008 160 12.016 320 48.065 480 42.057 160-6.009 320-54.073 480-60.082 160-6.008 320 30.041 400 48.065l80 18.025V137H0V30.708z"
fill="url(#aco1fmuv9c)"></path>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0 121.708 80 108.7c80-6.008 240-48.024 400-36.008 160 12.016 320 48.065 480 42.057 160-6.009 320-94.073 480-100.081 160-6.009 320 30.04 400 48.064l80 18.025V141H0v-19.292z"
fill="#fff"></path>
<defs>
<radialGradient
id="plkj8d2oga"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(960 0 0 41.5089 960 95.491)"
>
<stop stop-color="#FFFEFF"></stop>
<stop offset="1" stop-color="#D7FFFE"></stop>
</radialGradient>
<radialGradient
id="iwnto70uxb"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-652.99956 -34.96514 36.02623 -672.81617 1033.5 102.034)"
>
<stop stop-color="#BCFFFD"></stop>
<stop offset="1" stop-color="#fff" stop-opacity="0"></stop>
</radialGradient>
<radialGradient
id="aco1fmuv9c"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="rotate(8.473 63.69 3351.307) scale(825.005 723.955)"
>
<stop stop-color="#fff"></stop>
<stop offset="1" stop-color="#fff" stop-opacity="0"></stop>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,39 +0,0 @@
<script lang="ts">
import { createEventDispatcher } from "svelte"
import GeneralMediaImage from "./GeneralMediaImage.svelte"
const dispatch = createEventDispatcher()
</script>
<div class="scroll-to-top">
<div class="circle-email">
<a
href="/#"
on:click="{() => {
dispatch('scrollTo', {
element: 'contact',
})
}}"
>
<GeneralMediaImage id="contact" />
</a>
</div>
<div class="circle-contact">
<a
href="/#"
on:click="{() => {
dispatch('scrollTo', {
element: 'recipe',
})
}}"
>
<GeneralMediaImage id="recipe" />
</a>
</div>
<div class="circle-top">
<a href="/#">
<GeneralMediaImage id="up" />
</a>
</div>
</div>

View File

@@ -1,36 +0,0 @@
article,
.article {
overflow-wrap: anywhere;
border: 1px dashed @on-background;
padding: 2px;
& ~ article,
& ~ .article {
margin-top: @space-md;
}
.article-title {
color: @primary;
font-size: 2rem;
line-height: 2.4rem;
}
.article-subtitle {
color: @secondary;
font-size: 1.4rem;
line-height: 1.8rem;
}
.article-link {
cursor: pointer;
text-decoration: underline;
}
}
.article-details {
&.default {
}
&.news {
}
}

View File

@@ -1,18 +0,0 @@
.audioToggle {
position: fixed;
right: 17px;
bottom: 17px;
width: 80px;
height: 80px;
border-radius: 100%;
padding: 15px;
background-color: @secondary;
z-index: 1000;
cursor: pointer;
}
audio {
position: absolute;
top: -9999px;
left: -9999px;
}

View File

@@ -1,137 +0,0 @@
.carousel {
width: 100%;
height: 695px;
.carousel-slide {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: cover;
.container {
height: 100%;
}
img {
position: absolute;
right: 0;
bottom: 0;
@media (max-width: 1200px) {
display: none;
}
}
.content {
color: #fff;
text-shadow: 0 2px 10px #000;
font-weight: 700;
position: absolute;
top: 17rem;
left: 0;
@media (max-width: 768px) {
top: 10rem;
}
.headline {
font-family: "Caveat", sans-serif;
text-shadow: rgb(196, 37, 62) 6px 0px 0px,
rgb(196, 37, 62) 5.91686px 0.995377px 0px,
rgb(196, 37, 62) 5.66974px 1.96317px 0px,
rgb(196, 37, 62) 5.2655px 2.87655px 0px,
rgb(196, 37, 62) 4.71532px 3.71022px 0px,
rgb(196, 37, 62) 4.03447px 4.44106px 0px,
rgb(196, 37, 62) 3.24181px 5.04883px 0px,
rgb(196, 37, 62) 2.35931px 5.51667px 0px,
rgb(196, 37, 62) 1.41143px 5.83163px 0px,
rgb(196, 37, 62) 0.424423px 5.98497px 0px,
rgb(196, 37, 62) -0.574341px 5.97245px 0px,
rgb(196, 37, 62) -1.55719px 5.79441px 0px,
rgb(196, 37, 62) -2.49688px 5.45578px 0px,
rgb(196, 37, 62) -3.36738px 4.96596px 0px,
rgb(196, 37, 62) -4.14455px 4.33852px 0px,
rgb(196, 37, 62) -4.80686px 3.59083px 0px,
rgb(196, 37, 62) -5.33596px 2.74364px 0px,
rgb(196, 37, 62) -5.71718px 1.8204px 0px,
rgb(196, 37, 62) -5.93995px 0.84672px 0px,
rgb(196, 37, 62) -5.99811px -0.150428px 0px,
rgb(196, 37, 62) -5.89004px -1.14341px 0px,
rgb(196, 37, 62) -5.61874px -2.1047px 0px,
rgb(196, 37, 62) -5.19172px -3.00766px 0px,
rgb(196, 37, 62) -4.62082px -3.82727px 0px,
rgb(196, 37, 62) -3.92186px -4.54081px 0px,
rgb(196, 37, 62) -3.11421px -5.12852px 0px,
rgb(196, 37, 62) -2.22026px -5.57409px 0px,
rgb(196, 37, 62) -1.26477px -5.86518px 0px,
rgb(196, 37, 62) -0.274238px -5.99373px 0px,
rgb(196, 37, 62) 0.723898px -5.95617px 0px,
rgb(196, 37, 62) 1.70197px -5.75355px 0px,
rgb(196, 37, 62) 2.63288px -5.39147px 0px,
rgb(196, 37, 62) 3.49082px -4.87998px 0px,
rgb(196, 37, 62) 4.25202px -4.23324px 0px,
rgb(196, 37, 62) 4.89538px -3.46919px 0px,
rgb(196, 37, 62) 5.40307px -2.60899px 0px,
rgb(196, 37, 62) 5.76102px -1.67649px 0px,
rgb(196, 37, 62) 5.95932px -0.697531px 0px, 0 2px 20px #000;
line-height: 70px;
color: #fff;
font-weight: 700;
font-size: 96px;
@media (max-width: 768px) {
font-size: 72px;
}
}
.text {
font-size: 32px;
font-family: "Nunito", sans-serif;
margin-left: @space-md;
}
ul.text {
list-style-type: none;
padding-left: 30px;
li {
font-size: 32px;
font-family: "Nunito", sans-serif;
text-shadow: rgb(196, 37, 62) 3px 0px 0px,
rgb(196, 37, 62) 2.83487px 0.981584px 0px,
rgb(196, 37, 62) 2.35766px 1.85511px 0px,
rgb(196, 37, 62) 1.62091px 2.52441px 0px,
rgb(196, 37, 62) 0.705713px 2.91581px 0px,
rgb(196, 37, 62) -0.287171px 2.98622px 0px,
rgb(196, 37, 62) -1.24844px 2.72789px 0px,
rgb(196, 37, 62) -2.07227px 2.16926px 0px,
rgb(196, 37, 62) -2.66798px 1.37182px 0px,
rgb(196, 37, 62) -2.96998px 0.42336px 0px,
rgb(196, 37, 62) -2.94502px -0.571704px 0px,
rgb(196, 37, 62) -2.59586px -1.50383px 0px,
rgb(196, 37, 62) -1.96093px -2.27041px 0px,
rgb(196, 37, 62) -1.11013px -2.78704px 0px,
rgb(196, 37, 62) -0.137119px -2.99686px 0px,
rgb(196, 37, 62) 0.850987px -2.87677px 0px,
rgb(196, 37, 62) 1.74541px -2.43999px 0px,
rgb(196, 37, 62) 2.44769px -1.73459px 0px,
rgb(196, 37, 62) 2.88051px -0.838247px 0px,
0 2px 20px #000;
font-weight: 700;
&:before {
content: "»";
position: absolute;
left: -30px;
}
@media (max-width: 768px) {
font-size: 24px;
}
}
}
}
}
}

View File

@@ -1,59 +0,0 @@
.contact-information {
margin-top: -120px;
min-height: 1060px;
background: url("../css/theme-2022/components/img/union.svg") top no-repeat;
background-size: cover;
& > .container {
padding-top: 10rem;
}
.appointmentOfficeHour {
@media (max-width: 768px) {
font-size: 0.87em;
margin-bottom: @space-sm;
}
strong {
display: inline-block;
min-width: 120px;
}
}
.meeting-information {
margin-top: @space-xl;
}
ul {
list-style-type: none;
padding-left: 40px;
width: 100%;
li {
line-height: 30px;
padding-left: 0px;
font-weight: 400;
width: 50%;
display: inline-block;
@media (max-width: 768px) {
width: 100%;
}
&:before {
content: url("../css/theme-2022/components/img/check-bold.svg");
font-weight: 400;
top: 1px;
left: -30px;
}
}
}
@media (max-width: 1050px) {
padding-bottom: 10rem;
}
@media (max-width: 768px) {
margin-bottom: -90px;
}
}

View File

@@ -1,29 +0,0 @@
.top-of-content {
*[class^="col"] {
margin-bottom: @space-md;
}
display: flex;
justify-content: space-around;
align-items: stretch;
gap: @space-lg;
article {
width: 33%;
}
@media (max-width: 992px) {
flex-direction: column;
article {
width: 100%;
}
}
}
.wave-top {
height: 54px;
margin-top: -54px;
background-image: url("../css/theme/components/img/wave_header_top.png");
background-repeat: repeat-x;
}

View File

@@ -5,54 +5,11 @@ form {
border-radius: 10px;
box-shadow: 0 10px 40px 0 rgba(0, 0, 0, 0.1);
strong {
color: @primary;
font-weight: 700;
}
.titles {
flex-grow: 1;
.title,
.subTitle {
text-align: left;
color: @on-surface;
margin: 0;
}
}
.icon {
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
border-radius: 100%;
img {
width: 50%;
}
}
.collapse-icon {
cursor: pointer;
svg {
transition: @transition-default;
}
&.collapsed svg {
transform: rotate(-90deg);
}
}
input,
textarea,
.checkbox {
cursor: pointer;
border: 1px solid transparent;
border-radius: 10px;
box-shadow: inset 0 0 10px 0 rgba(0, 0, 0, 0.1);
background: @surface;
color: @on-background;
padding: @space-sm @space-md;
@@ -76,7 +33,7 @@ form {
&:focus {
border: 1px solid @primary;
color: @primary;
color: @on-surface;
}
&[readonly] {
@@ -86,15 +43,22 @@ form {
.checkbox {
padding: 0;
width: 60px;
height: 60px;
width: 30px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
color: @primary;
.icon {
svg {
width: 90% !important;
height: 90% !important;
}
}
&:hover {
box-shadow: inset 0 0 10px 0 @primary;
box-shadow: inset 0 0 1px 1px @primary;
}
}

View File

@@ -19,51 +19,6 @@ body {
}
}
// Scroll To Top
.scroll-to-top {
position: fixed;
z-index: 9999;
right: 5rem;
bottom: 5rem;
@media (max-width: 768px) {
right: 4rem;
bottom: 1rem;
}
.circle-top,
.circle-email,
.circle-contact {
width: 80px;
height: 80px;
border-radius: 100%;
background-color: @secondary;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
.circle-email {
width: 60px;
height: 60px;
background-color: @secondary;
position: absolute;
top: -20px;
right: -39px;
}
.circle-contact {
width: 60px;
height: 60px;
background-color: @secondary;
position: absolute;
top: 23px;
right: -53px;
}
}
// 404
.page-404 {

View File

@@ -1,50 +0,0 @@
.history {
font-size: 24px;
font-weight: 700;
.history-item {
min-height: 80px;
.date {
width: 80px;
height: 80px;
border-radius: 100%;
background-color: @secondary;
color: @on-secondary;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
position: absolute;
top: -21px;
left: calc(50% - 40px);
}
.text {
width: 41%;
}
&:nth-child(odd) {
.text {
margin-left: auto;
}
}
& ~ .history-item {
margin-top: @space-md;
}
@media (max-width: 900px) {
.date {
left: 0;
}
&:nth-child(odd),
&:nth-child(even) {
.text {
width: 100%;
padding-left: 100px;
font-size: 0.7em;
}
}
}
}
}

View File

@@ -1,23 +0,0 @@
.language-chooser {
display: flex;
justify-content: flex-end;
align-items: center;
margin: @space-xs;
.lang {
border: 1px solid @secondary;
padding: 0 @space-xs;
cursor: pointer;
&:hover {
background: @primary;
color: @on-primary;
}
&.active {
background: @primary;
color: @on-primary;
font-weight: 700;
}
}
}

View File

@@ -1,19 +0,0 @@
.news {
article {
background: @surface;
color: @on-surface;
padding: @space-sm @space-md;
border-radius: 10px;
box-shadow: 0 10px 40px 0 rgba(0, 0, 0, 0.1);
margin-bottom: @space-lg;
@media (max-width: 768px) {
text-align: center;
}
.title {
font-weight: 700;
margin-bottom: @space-xs;
}
}
}

View File

@@ -1,12 +0,0 @@
.promotion-image-wave-top,
.promotion-image-wave-bottom {
z-index: 2;
width: 100%;
}
.promotion-image {
z-index: 0;
margin-top: -56px;
margin-bottom: -68px;
width: 100%;
}

View File

@@ -1,52 +0,0 @@
.services {
article {
font-weight: 700;
display: flex;
align-items: flex-start;
gap: @space-sm;
margin-bottom: @space-xs;
padding: @space-sm @space-md;
border-radius: 10px;
cursor: pointer;
&:hover {
background: @surface;
color: @on-surface;
box-shadow: 0 10px 40px 0 rgba(0, 0, 0, 0.1);
}
.icon {
width: 50px;
height: 50px;
border-radius: 100%;
background-color: @secondary;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
img {
height: 32px;
margin-top: 2px;
}
}
.title {
font-size: 24px;
font-weight: 700;
@media (max-width: 768px) {
font-size: 20px;
}
}
@media (max-width: 768px) {
padding: 0;
&:hover {
background: transparent;
box-shadow: none;
}
}
}
}

View File

@@ -1,42 +0,0 @@
.sidebar {
.contact-info {
color: @primary;
font-size: 18px;
font-weight: 600;
}
.today {
padding: 5px 20px;
border-radius: 25px;
border: solid 3px #000;
font-weight: 700;
}
.lastPageUpdate {
text-align: center;
.lastPageUpdate-date {
font-weight: 700;
font-size: 18px;
margin-top: @space-xs;
}
}
.visitor-counter {
h3 {
margin-bottom: @space-xs;
}
table {
width: 100% !important;
max-width: 100% !important;
display: block !important;
td {
width: 100%;
font-family: "Nunito", sans-serif;
font-size: @font-size-default;
line-height: auto;
padding: @space-xs 0;
}
}
}
}

View File

@@ -1,79 +0,0 @@
.specials {
article {
background: @surface;
color: @on-surface;
padding: @space-md;
border-radius: 10px;
box-shadow: 0 10px 40px 0 rgba(0, 0, 0, 0.1);
margin-bottom: @space-lg;
font-weight: 700;
display: flex;
justify-content: flex-start;
align-items: center;
gap: @space-md;
@media (max-width: 768px) {
flex-direction: column;
text-align: center;
}
.icon {
width: 80px;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
@media (max-width: 768px) {
width: 50px;
height: 50px;
}
img {
width: 100%;
}
}
.title {
margin-bottom: @space-xs;
font-size: 24px;
line-height: 1.3;
@media (max-width: 768px) {
font-size: 20px;
}
}
&.hovered {
display: none;
@media (min-width: 768px) {
display: flex;
position: fixed;
top: 40%;
left: 30%;
right: 30%;
z-index: 999;
box-shadow: inset 0 0 2px 1px white, 0 10px 40px 0 rgba(0, 0, 0, 0.1), 0 10px 40px 0 rgba(0, 0, 0, 0.1);
background: linear-gradient(
90deg,
rgba(238, 254, 255, 1) 0%,
rgba(255, 254, 255, 1) 35%,
rgba(215, 255, 254, 1) 100%
),
radial-gradient(88.73% 230.98% at 25.76% 13.14%, #ffffff 0%, rgba(255, 255, 255, 0) 100%),
radial-gradient(50% 20.05% at 50% 46.13%, #fffeff 0%, #d7fffe 100%);
}
}
}
.row:nth-child(2) > *:nth-child(2) > article:first-child {
margin-top: @space-xl;
@media (max-width: 1050px) {
margin-top: 0;
}
}
}

View File

@@ -1,50 +0,0 @@
.top-section {
height: 1003px;
margin-bottom: -28rem;
@media (max-width: 1050px) {
margin-bottom: 0rem;
}
.text {
margin-top: @space-xl;
strong {
color: @secondary;
}
}
.top-section-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
@media (max-width: 768px) {
height: 64rem;
object-fit: cover;
}
}
.circles {
position: absolute;
top: -151px;
left: -97px;
min-width: 986px;
@media (max-width: 1049px) {
top: -151px;
left: -97px;
}
}
.circles-image {
position: absolute;
top: 0;
left: 70px;
min-width: 550px;
@media (max-width: 1240px) {
min-width: 652px;
}
}
}

View File

@@ -35,22 +35,15 @@
@import "components/general";
@import "components/grid";
@import "components/typo";
@import "components/layout";
@import "components/typo";
@import "components/section";
@import "components/header";
@import "components/footer";
@import "components/navigation";
@import "components/news";
@import "components/services";
@import "components/specials";
@import "components/iframes";
@import "components/contact-information";
@import "components/promotion-image";
@import "components/history";
@import "components/top-section";
@import "components/forms";
@import "components/language-chooser";
@import "components/article";
// Overwrite styles from Webmakers Cookie-Bar
@import "components/cc-bar";

View File

@@ -1,5 +1,5 @@
import { writable, get } from "svelte/store"
import { getGeneralInformation, getArticles, getNavigations } from "./api"
import { getGeneralInformation, getNavigations } from "./api"
// Localtion
@@ -36,6 +36,8 @@ getGeneralProjectInformation()
// Navigations
export const showMobileNav = writable<boolean>(false)
export const navigations = writable<Navigation[]>([])
const getAllNavigations = async (locale: Locale) => {
const list = await getNavigations(locale)