most of it

This commit is contained in:
2023-09-18 17:31:11 +00:00
parent 5f27fe0c5b
commit 481308522f
380 changed files with 3015 additions and 2480 deletions

View File

@@ -7,10 +7,9 @@ DirectoryIndex spa.html
RewriteEngine On
RewriteBase /
RewriteRule ^/?api/(.*)$ http://tibi-server:8080/api/v1/_/wasserski_erfurt/$1 [P,QSA,L]
RewriteRule ^/?api/(.*)$ http://tibi-server:8080/api/v1/_/allkids_erfurt/$1 [P,QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^/?(.*)$ http://tibi-server:8080/api/v1/_/wasserski_erfurt/ssr?token=owshwerNwoa&url=/$1 [P,QSA,L]
RewriteRule (.*) /spa.html [QSA,L]
</ifModule>

View File

@@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 6.41 6.41 5 17 15.59V9h2v10H9v-2h6.59L5 6.41z" fill="#4b678b"/>
<path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z" fill="#9fb3c7"/>
</svg>

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 202 B

View File

@@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z" fill="#4b678b"/>
<path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z" fill="#672129"/>
</svg>

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 202 B

View File

@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 199 B

View File

@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 10h5v5H7m12 4H5V8h14m0-5h-1V1h-2v2H8V1H6v2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2z" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 244 B

View File

@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.5 16.8c-.7 0-1.2-.6-1.2-1.2 0-.7.6-1.2 1.2-1.2s1.2.6 1.2 1.2c.1.6-.5 1.2-1.2 1.2zm0-4.8c-1.9 0-3.5 1.6-3.5 3.5 0 2.6 3.5 6.5 3.5 6.5s3.5-3.9 3.5-6.5c0-1.9-1.6-3.5-3.5-3.5zM9 2 7 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h10.5c-.6-.9-1.1-1.9-1.4-3.1-.3.1-.7.1-1.1.1-2.8 0-5-2.2-5-5s2.2-5 5-5c2.1 0 4 1.3 4.7 3.3.6-.2 1.2-.3 1.8-.3 1.3 0 2.5.5 3.5 1.3V6c0-1.1-.9-2-2-2h-3l-2-2H9zm2.9 7C10.3 9 9 10.4 9 12c0 1.7 1.3 3 3 3 .4 0 .7-.1 1-.2.2-1.4.9-2.6 1.9-3.5-.3-1.3-1.5-2.3-3-2.3.1 0 .1 0 0 0z" fill="#4b678b"/>
</svg>

Before

Width:  |  Height:  |  Size: 622 B

View File

@@ -1,3 +0,0 @@
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 3.06c-8.25 0-15 6.735-15 15.03 0 7.5 5.49 13.725 12.66 14.85v-10.5h-3.81v-4.35h3.81v-3.315c0-3.765 2.235-5.835 5.67-5.835 1.635 0 3.345.285 3.345.285v3.705h-1.89c-1.86 0-2.445 1.155-2.445 2.34v2.82h4.17l-.675 4.35H20.34v10.5A15 15 0 0 0 33 18.09c0-8.295-6.75-15.03-15-15.03z" fill="#4b678b"/>
</svg>

Before

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

Binary file not shown.

17
frontend/media/logo.svg Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100%" height="100%" fill="rgba(207,165,149,0)"/>
<g transform="matrix(4.995999813079834, 0, 0, 4.995999813079834, 501.0972900390626, 499.6000061035156)" id="495873">
<filter id="SVGID_40" y="-20%" height="140%" x="-20%" width="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="0"/>
<feOffset dx="0" dy="0" result="oBlur"/>
<feFlood flood-color="rgb(0,0,0)" flood-opacity="0"/>
<feComposite in2="oBlur" operator="in"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<path style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; is-custom-font: none; font-file-url: none; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;filter: url(#SVGID_40);" vector-effect="non-scaling-stroke" d="M 112.787 80.919 L 134.765 125.275 L 114.985 125.275 L 100.599 95.904 L 77.822 126.074 L 77.822 200 L 59.84 200 L 59.84 110.09 L 77.822 79.52 L 77.822 104.695 L 147.952 0 L 168.731 0 L 131.768 54.545 L 112.787 80.919 Z M 77.822 0 L 77.822 38.162 L 59.84 68.931 L 59.84 0 L 77.822 0 Z M 120.38 38.561 L 109.79 54.346 L 100.2 38.162 L 47.652 127.073 L 58.042 127.073 L 58.042 141.059 L 39.261 141.059 L 19.481 174.625 L -0.3 174.625 L 87.413 25.774 L 99.732 4.555 L 112.587 25.774 L 120.38 38.561 Z M 200.3 174.625 L 180.719 174.625 L 160.939 141.059 L 79.82 141.059 L 79.82 127.073 L 152.547 127.073 L 120.779 73.127 L 131.568 57.942 L 200.3 174.625 Z M 170.929 200 L 150.35 200 L 123.576 142.857 L 143.556 142.857 L 170.929 200 Z" stroke-linecap="round" transform=" translate(-100, -100)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 13V5a3 3 0 0 0-6 0v8a5 5 0 1 0 6 0zm-3-9a1 1 0 0 1 1 1v3h-2V5a1 1 0 0 1 1-1z" fill="#4b678b"/>
</svg>

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 12h2v2h-2c-1.38 0-2.74-.35-4-1-2.5 1.3-5.5 1.3-8 0-1.26.65-2.63 1-4 1H2v-2h2c1.39 0 2.78-.47 4-1.33 2.44 1.71 5.56 1.71 8 0 1.22.86 2.61 1.33 4 1.33zm0-6h2v2h-2c-1.38 0-2.74-.35-4-1-2.5 1.3-5.5 1.3-8 0-1.26.65-2.63 1-4 1H2V6h2c1.39 0 2.78-.47 4-1.33 2.44 1.71 5.56 1.71 8 0C17.22 5.53 18.61 6 20 6zm0 12h2v2h-2c-1.38 0-2.74-.35-4-1-2.5 1.3-5.5 1.3-8 0-1.26.65-2.63 1-4 1H2v-2h2c1.39 0 2.78-.47 4-1.33 2.44 1.71 5.56 1.71 8 0 1.22.86 2.61 1.33 4 1.33z" fill="#4b678b"/>
</svg>

Before

Width:  |  Height:  |  Size: 589 B

View File

@@ -1 +0,0 @@
<svg id="e75HGxgJUV31" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 29.9 450" shape-rendering="geometricPrecision" text-rendering="geometricPrecision"><path d="M29.925258,450.800658c2.416953,17.862542,0-224.999303.074742-438.639846-.024742.014818-.049485.030164-.074742.044982-.723711.42918-1.540722.775806-2.48866,1.001244-2.735567.650915-5.713402.150293-7.978351-1.338873-2.219588-1.46006-3.644845-4.042551-3.391237-6.139237.180412-1.504513,1.157732-2.672984,2.826289-3.379994.229897-.098431.272165-.275713.276804-.372556.009278-.18522-.097938-.355093-.285052-.450348-1.480412-.755167-4.034021-1.34099-7.715979.218559-2.266495.956263-4.109794,3.095285-6.057732,5.357611C3.555155,8.907826,1.946907,10.775369,0,12.161342l.1,438.639319l29.825258-.000003Z" transform="matrix(1 0 0 1.000003-.1-.802011)"/></svg>

Before

Width:  |  Height:  |  Size: 856 B

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Wasserski Erfurt</title>
<title>AllKids Erfurt</title>
<base href="/" />
<link rel="stylesheet" href="/dist/index.css?t=__TIMESTAMP__" />
<script
@@ -12,6 +12,7 @@
src="https://unpkg.com/external-svg-loader@latest/svg-loader.min.js"
async
></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/4.1.1/less.min.js"></script>
<!--HEAD-->
<!--PRELOAD-->
@@ -33,4 +34,4 @@
<!--SSR.ERROR-->
<!--SSR.COMMENT-->
</html>
</html>

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { location, navigation, sites, temperature, banner, serviceNavigation} from "./lib/stores"
import { location, navigation, sites, temperature, banner, serviceNavigation } from "./lib/stores"
import Header from "./lib/components/header/Header.svelte"
import Footer from "./lib/components/Footer.svelte"
import { Route, Router } from "svelte-routing"
@@ -8,12 +8,13 @@
import { loadBanner } from "./lib/functions/loadBanner"
import { loadSites } from "./lib/functions/loadSites"
import { loadTemperature } from "./lib/functions/loadTemperature"
import Site from "./routes/Site.svelte"
import Banner from "./lib/components/pagebuilder/banner.svelte"
import SiteComp from "./routes/Site.svelte"
import NotFound from "./routes/NotFound.svelte"
import insta from "../media/instagram.svg"
import BannerComp from "./lib/components/pagebuilder/banner.svelte"
import ScrollTop from "./lib/components/pagebuilder/scrollTop.svelte"
import ScrollDown from "./lib/components/pagebuilder/scrollDown.svelte"
export let url = ""
if (url) {
// ssr
let l = url.split("?")
@@ -28,38 +29,37 @@
}
async function getNavigation() {
let nav: Navigation = await loadNavigation()
let nav: Navigation[] = await loadNavigation()
$navigation = nav[0]
$serviceNavigation = nav[1]
}
async function getBanner() {
let banner: Banner[] = await loadBanner()
console.log(banner)
$banner = banner
let bannerRes: Banner[] = await loadBanner()
$banner = bannerRes
}
async function getSites() {
let sitesArray: Site[] = await loadSites()
let sites: Sites = {}
let sitesRes: Sites = {}
sitesArray.forEach((e) => {
sites[e.id] = e
sitesRes[e.id] = e
})
$sites = sites
$sites = sitesRes
console.log("ALARM OVER", $sites)
}
async function getTemperature() {
let temperature = await loadTemperature()
console.log(temperature)
$temperature = temperature.temperature.toFixed(2)
}
getNavigation()
getSites()
getBanner()
getTemperature()
$: {
if (Object.values($sites).length == 0) {
getSites()
}
}
// scroll to top on new site
location.subscribe((l) => {
if (l.push) scrollToTop()
if (l.push) scrollTo({ top: 0 })
})
</script>
@@ -71,7 +71,8 @@
<HomePage />
</Route>
<Route path="/*path" let:params>
<Site path="{params.path}" />
{#key $sites}
<SiteComp path="{params.path}" />{/key}
</Route>
<Route>
<NotFound />
@@ -79,21 +80,25 @@
</Router>
<Footer />
</div>
<button class="arrow-up" on:click="{() => window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })}"
><img src="media/arrow-up.svg" alt="arrow" /></button
>
<Banner />
<button class="arrow-up" on:click="{() => window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })}"> </button>
<ScrollTop />
<ScrollDown />
<BannerComp />
<div class="socialMedia">
<a target="_blank" href="https://www.instagram.com/wasserski_erfurt/"
><img src="media/instagram.svg" alt="insta" /></a
>
<a target="_blank" href="https://www.facebook.com/wasserskierfurt/"><img src="media/facebook.svg" alt="fb" /></a
>
<a target="_blank" href="https://www.facebook.com/allkids.erfurt/">
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M18 3.06c-8.25 0-15 6.735-15 15.03 0 7.5 5.49 13.725 12.66 14.85v-10.5h-3.81v-4.35h3.81v-3.315c0-3.765 2.235-5.835 5.67-5.835 1.635 0 3.345.285 3.345.285v3.705h-1.89c-1.86 0-2.445 1.155-2.445 2.34v2.82h4.17l-.675 4.35H20.34v10.5A15 15 0 0 0 33 18.09c0-8.295-6.75-15.03-15-15.03z"
fill="var(--link-font-color)"></path>
</svg>
</a>
</div>
</main>
<style lang="less">
@import "./lib/assets/css/main.less";
@import "./lib/assets/css/variables.less";
@import "./lib/assets/css/fonts.less";
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
@@ -107,6 +112,14 @@
url("./lib/assets/fonts/roboto-condensed-v25-latin-regular.ttf") format("truetype"),
url("./lib/assets/fonts/roboto-condensed-v25-latin-regular.svg") format("svg");
}
/* orbitron-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Orbitron";
font-style: normal;
font-weight: 900;
src: url("./lib/assets/fonts/orbitron-v31-latin-900.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
.socialMedia {
display: none;
@@ -133,31 +146,18 @@
display: flex;
align-items: center;
flex-direction: column;
color: @normal-font-color;
.arrow-up {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
bottom: 10px;
right: 10px;
height: 2rem;
width: 2rem;
border-radius: 50%;
z-index: 1000;
background-color: @link-font-color;
img {
transform-origin: center;
}
}
color: var(--normal-font-color);
.content-container {
display: flex;
z-index: 10;
min-height: 100vh;
flex-direction: column;
width: 100%;
align-items: center;
overflow: hidden;
justify-content: center;
justify-content: space-between;
}
}
@media (min-width: 1800px) {

View File

@@ -31,7 +31,7 @@ const publishLocation = (_p?: string) => {
if (typeof history !== "undefined") {
if (typeof Proxy !== "undefined") {
// modern browser
const historyApply = (target, thisArg, argumentsList) => {
const historyApply = (target: (this: any, ...args: readonly any[]) => unknown, thisArg: any, argumentsList: string | readonly any[]) => {
publishLocation(argumentsList && argumentsList.length >= 2 && argumentsList[2])
Reflect.apply(target, thisArg, argumentsList)
}

View File

@@ -0,0 +1,142 @@
.underline {
display: inline;
position: relative;
overflow: hidden;
}
.underline:after {
content: "";
position: absolute;
z-index: 10000;
right: 0;
width: 0;
bottom: -2px;
background: var(--background-color);
height: 4px;
transition: width 0.5s ease-in;
}
.underline:hover:after,
.underline:focus:after,
.underline:active:after {
left: 0;
right: auto;
width: 100%;
}
.fill {
display: inline;
position: relative;
overflow: hidden;
}
.fill:hover {
color: var(--background-color) !important;
div {
position: relative;
z-index: 2;
}
}
.fill:after {
content: "";
position: absolute;
z-index: 1;
right: 0;
top: 0px;
bottom: 0px;
width: 0px;
background: var(--opposite-bg-color);
transition: width 0.5s ease-in;
}
.fill:hover:after,
.fill:focus:after,
.fill:active:after {
right: auto;
width: 100%;
left: 0px;
}
@keyframes underlineEffect {
0% {
width: 0;
}
100% {
width: 100%;
}
}
swiper-slide {
&:hover {
h1.active .underline {
animation-play-state: paused;
}
}
}
.titles {
h1 {
.underline {
position: absolute;
z-index: 10000;
left: 0px;
bottom: -10px;
background: var(--opposite-bg-color);
height: 5px;
width: 0;
animation: underlineEffect 4s linear forwards;
@media @tablet {
height: 10px;
}
}
&:not(.active) .underline {
animation: none;
}
}
}
.swiper-button-prev,
.swiper-button-next {
color: var(--normal-font-color) !important;
height: 70px !important;
width: 70px !important;
bottom: 0px !important;
top: initial !important;
transform: scale(0.5) !important;
}
.swiper-button-prev {
right: 18% !important;
left: initial !important;
transform-origin: left !important;
}
.swiper-button-next {
right: 3% !important;
transform-origin: right;
}
@media @tablet {
.swiper-button-prev,
.swiper-button-next {
bottom: initial !important;
top: 120px !important;
transform: scale(0.8) !important;
transform-origin: center !important;
}
.swiper-button-prev {
left: 0% !important;
right: initial !important;
transform-origin: left !important;
}
.swiper-button-next {
right: 0% !important;
transform-origin: right !important;
}
}
@media @desktop {
.swiper-button-prev,
.swiper-button-next {
top: 125px !important;
transform: scale(1) !important;
}
}

View File

@@ -1,26 +1,33 @@
@background-color: white;
@normal-font-color: #333333;
@hover-color: #dee2e6;
@heading-font-color: #4b678b;
@link-font-color: #4b678b;
@banner-color: #06d6a0;
:root {
--background-color: white;
--background-color-90: #ffffffe6;
--normal-font-color: #333333;
--normal-font-color-12: rgba(51, 51, 51, 0.12);
--hover-color: #dee2e6;
--heading-font-color: #672129;
--link-font-color: #672129;
--banner-color: #06d6a0;
--opposite-bg-color: #000;
--opposite-bg-color-80: rgba(0, 0, 0, 0.8);
--opposite-bg-color-5: rgba(0, 0, 0, 0.05);
}
@desktop: ~"only screen and (min-width: 1024px)";
@tablet: ~"only screen and (min-width: 768px)";
@mobile: ~"only screen and (min-width: 100px)";
@body-fontsize-mobile: 17px;
@body-fontsize-pc: 24px;
@body-fontsize-mobile: 16px;
@body-lineheight-mobile: 130%;
@body-lineheight-pc: 130%;
@body-maxwidth: 1800px;
@body-small-maxwidth: 1200px;
/* Allgemeine Stile */
/* roboto-condensed-regular - latin */
body.darkTheme {
--background-color: #1a1a1a; /* softer than #121212 */
--background-color-90: rgba(26, 26, 26, 0.9);
--normal-font-color: #d1d1d1; /* off-white, less harsh */
--normal-font-color-12: rgba(209, 209, 209, 0.12);
--hover-color: #404040; /* subtle change for hover */
--heading-font-color: #9fb3c7; /* slightly brighter for better readability */
--link-font-color: #9fb3c7;
--banner-color: #04a577; /* a cooler shade for the banner */
--opposite-bg-color: #fafafa; /* off-white */
--opposite-bg-color-80: rgba(250, 250, 250, 0.8);
--opposite-bg-color-5: rgba(250, 250, 250, 0.05);
.row ul li::before {
background-image: url("../../../../media/arrow-right-darkt.svg") !important;
}
}
* {
font-family: "Roboto Condensed", sans-serif;
@@ -30,14 +37,13 @@
}
body {
font-family: "Roboto Condensed", sans-serif;
color: #333 !important;
height: 100%;
background-color: #f9f9f9;
overflow-x: hidden !important;
}
body {
background-color: @background-color;
color: var(--normal-font-color);
font-family: "Roboto Condensed", sans-serif;
background-color: var(--background-color);
min-height: 100vh;
display: flex;
justify-content: center;
@@ -69,8 +75,8 @@ ol {
/* Links */
a {
color: @link-font-color;
text-decoration: none;
color: var(--link-font-color);
text-decoration: underline;
font-weight: 700;
}
@@ -94,20 +100,17 @@ td {
}
th {
background-color: #f4f4f4;
background-color: var(--background-color-90);
}
button {
background-color: inherit;
border: none;
cursor: pointer;
font-size: inherit;
color: #333;
color: var(--normal-font-color);
}
input,
select {
color: #333;
color: var(--normal-font-color);
width: 100%;
}
.text-container {
}

View File

@@ -0,0 +1,6 @@
swiper-container {
height: auto;
width: 100%;
max-width: 1200px;
padding: 20px !important;
}

View File

@@ -1,19 +1,21 @@
.swiper-button-prev,
.swiper-button-next {
transform-origin: left;
color: #333;
transform: scale(0.3);
background-color: rgba(255, 255, 255, 0.6);
top: 50%;
padding: 10px;
height: 70px;
width: 70px;
border-radius: 50px;
}
.swiper-button-prev {
left: 6%;
}
.swiper-button-next {
right: 6%;
transform-origin: right;
.images {
.swiper-button-prev,
.swiper-button-next {
transform-origin: left;
color: var(--normal-font-color);
transform: scale(0.3);
background-color: rgba(255, 255, 255, 0.6);
top: 50%;
padding: 10px;
height: 70px;
width: 70px;
border-radius: 50px;
}
.swiper-button-prev {
left: 6%;
}
.swiper-button-next {
right: 6%;
transform-origin: right;
}
}

View File

@@ -1,13 +1,4 @@
@background-color: white;
@normal-font-color: #333333;
@hover-color: #dee2e6;
@heading-font-color: #4b678b;
@link-font-color: #4b678b;
@banner-color: #06d6a0;
@desktop: ~"only screen and (min-width: 1024px)";
@tablet: ~"only screen and (min-width: 768px)";
@mobile: ~"only screen and (min-width: 100px)";
@body-fontsize-mobile: 17px;
@body-fontsize-pc: 24px;
@@ -17,3 +8,7 @@
@body-maxwidth: 1800px;
@body-small-maxwidth: 1200px;
@desktop: ~"only screen and (min-width: 1024px)";
@tablet: ~"only screen and (min-width: 768px)";
@mobile: ~"only screen and (min-width: 100px)";

View File

@@ -5,32 +5,24 @@
<div class="footer">
<div class="infos">
<h3>Wasserski Erfurt</h3>
<h3>AllKids Erfurt</h3>
<div class="infos-inner">
<div class="upper">
<p>Inh. Michael Sadlon</p>
<p>Zum Nordstrand 4</p>
<p>99085 Erfurt</p>
<p>Inh. Grit Grenzdörfer</p>
<p>Eichenstraße 8</p>
<p>99084 Erfurt</p>
</div>
<div class="lower">
<p>Tel.: 0361 - 796 876 4</p>
<p>Fax.: 0361 - 796 876 8</p>
<p>Email: info@wasserski-erfurt.de</p>
<p>Tel.: <a href="tel:+491784124555">0178 4124555</a></p>
<p>Email: <a href="mailto:kiro0206@icloud.com">kiro0206@icloud.com</a></p>
</div>
</div>
<div class="social">
<a href="https://www.instagram.com/wasserski_erfurt/">
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.7 3h12.6c4.8 0 8.7 3.9 8.7 8.7v12.6a8.7 8.7 0 0 1-8.7 8.7H11.7C6.9 33 3 29.1 3 24.3V11.7A8.7 8.7 0 0 1 11.7 3zm-.3 3A5.4 5.4 0 0 0 6 11.4v13.2c0 2.985 2.415 5.4 5.4 5.4h13.2a5.4 5.4 0 0 0 5.4-5.4V11.4C30 8.415 27.585 6 24.6 6H11.4zm14.475 2.25a1.875 1.875 0 1 1 0 3.75 1.875 1.875 0 0 1 0-3.75zM18 10.5a7.5 7.5 0 1 1 0 15 7.5 7.5 0 0 1 0-15zm0 3a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9z"
fill="#333333"></path>
</svg>
</a>
<a href="https://www.facebook.com/wasserskierfurt/">
<a href="https://www.facebook.com/allkids.erfurt/">
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M18 3.06c-8.25 0-15 6.735-15 15.03 0 7.5 5.49 13.725 12.66 14.85v-10.5h-3.81v-4.35h3.81v-3.315c0-3.765 2.235-5.835 5.67-5.835 1.635 0 3.345.285 3.345.285v3.705h-1.89c-1.86 0-2.445 1.155-2.445 2.34v2.82h4.17l-.675 4.35H20.34v10.5A15 15 0 0 0 33 18.09c0-8.295-6.75-15.03-15-15.03z"
fill="#333333"></path>
fill="var(--normal-font-color)"></path>
</svg>
</a>
</div>
@@ -39,11 +31,19 @@
{#each $serviceNavigation?.elemente || [] as service, i (i)}
<button
on:click="{() => {
navigate(`${$sites[service.seite]?.path}`)
navigate(`${$sites[service.seite || '']?.path}`)
}}">{service?.name}</button
>
{/each}
</div>
<button
on:click="{() => {
const body = document.querySelector('body')
if (body) body.classList.toggle('darkTheme')
}}"
>
toggletheme
</button>
</div>
<style lang="less">
@@ -58,7 +58,7 @@
display: flex;
justify-content: space-between;
max-width: calc(@body-maxwidth - min(9vw, 200px));
background-color: @hover-color;
background-color: var(--hover-color);
padding: min(4.5vw, 100px) min(4.5vw, 100px) 0px min(4.5vw, 100px);
}
.infos {
@@ -91,17 +91,15 @@
@media @tablet {
gap: 40px;
}
height: 350px;
min-height: 350px;
.infos-inner {
flex-direction: column;
}
}
.footer {
}
}
@media @desktop {
.footer {
height: 350px;
min-height: 350px;
.infos-inner {
gap: 5vw;
flex-direction: row;

View File

@@ -1,7 +1,7 @@
<script lang="ts">
export let cookieName
export let cookieName: string
export let backgroundUrl = ""
export let textPosition = "center"
export let textPosition: "oben" | "mitte" | "unten" = "mitte"
export let background = ""
let contentShown = false
const positions = {
@@ -11,15 +11,16 @@
}
window.addEventListener("ccAccept", (e) => {
// @ts-ignore
if (e.detail[1] == cookieName) contentShown = true
})
//isCookieSet isnt really precise
function checkCookie(name) {
function checkCookie(cookieName: string) {
// Get all cookies
var allCookies = decodeURIComponent(document.cookie)
// Split into individual cookies
var cookies = allCookies.split(";")
var ccTagCookies = []
var ccTagCookies: string[] = []
cookies.forEach((e) => {
e.includes("ccTags") ? (ccTagCookies = e.split(",")) : void 0
})

View File

@@ -3,18 +3,19 @@
import CookieSet from "./cookieSet.svelte"
$: iframeTitle = "testrest"
let setHeight = (element) => {
let setHeight = (element: HTMLIFrameElement) => {
element.style.height = (element.offsetWidth / 16) * 9 + "px"
}
</script>
<CookieSet cookieName="{'googleMaps'}" textPosition="{'unten'}" background="{'rgba(44, 44, 44, 0.4)'}">
<!-- svelte-ignore a11y-missing-attribute -->
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d20097.11535738499!2d11.016094258611309!3d50.976613538609506!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47a47295445dec17%3A0x78ec05d774043a43!2sall%20kids%20-%20Secondhand%20Kinderbekleidung!5e0!3m2!1sde!2sde!4v1694951373813!5m2!1sde!2sde"
use:setHeight
id="iframe"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2510.8843160281504!2d11.046507612986247!3d50.99980984753832!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47a46d575a841fe1%3A0xd6703e9ebe1ca279!2sErfurt%20Wasserski-%20und%20Wakeboardanlage!5e0!3m2!1sde!2sde!4v1682691189533!5m2!1sde!2sde"
style="border:0;"
allowfullscreen=""
allowfullscreen="{true}"
loading="lazy"
referrerpolicy="no-referrer-when-downgrade"></iframe>
</CookieSet>

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import DesktopHeader from "./desktop.svelte"
import MobileHeader from "./mobile.svelte"
import { navigation } from "../../stores"
</script>
<main class="headercontainer">
@@ -18,7 +17,17 @@
<style global lang="less">
@import "../../assets/css/main.less";
@import "../../assets/css/variables.less";
@desktop: ~"only screen and (min-width: 1440px)";
.HP {
h2 {
font-size: 2.1rem !important;
@media @tablet {
font-size: 3.2rem !important;
}
}
}
.ignore {
display: none !important;
@@ -28,6 +37,7 @@
position: relative;
height: 100%;
width: 100%;
}
.placeholder {
height: 105px;
@@ -39,8 +49,9 @@
top: 0px;
justify-content: space-between;
width: 100%;
color: #333;
color: var(--normal-font-color);
height: 105px;
}
@media @desktop {
.headercontainer,

View File

@@ -10,9 +10,10 @@
else siteContainer.style.overflow = "initial"
}
async function changeSubmenu(e, i) {
async function changeSubmenu(e: EventTarget & HTMLLIElement, i: string | number) {
changeStateOfSite(true)
let submenu = document.getElementById("submenu-container")
if (!submenu) return
submenu.style.height = "calc(100vh - 120px)"
submenu.classList.add("show-submenu")
@@ -21,23 +22,27 @@
element.classList.remove("shown")
})
let shownMenu = document.getElementById("submenu-" + i)
if (!shownMenu) return
shownMenu.classList.add("shown")
}
let hoverTimeout
let hoverTimeout: string | number | NodeJS.Timeout | undefined
</script>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<ul
class="menu"
on:mouseover="{(e) => {
clearTimeout(hoverTimeout)
hoverTimeout = setTimeout(() => {
let element = document.getElementById('submenu-container')
element.style.height = '0vh'
changeStateOfSite(false)
element.classList.remove('show-submenu')
let elements = document.getElementsByClassName('select-menu')
Array.from(elements).forEach((e) => e.classList.remove('select-menu'))
if (element) {
element.style.height = '0vh'
changeStateOfSite(false)
element.classList.remove('show-submenu')
let elements = document.getElementsByClassName('select-menu')
Array.from(elements).forEach((e) => e.classList.remove('select-menu'))
}
}, 500)
}}"
on:mouseleave="{() => {
@@ -48,27 +53,34 @@
class="logo-container"
on:click="{() => {
let element = document.getElementById('submenu-container')
if (!element) return
element.style.height = '0vh'
element.classList.remove('show-submenu')
changeStateOfSite(false)
navigate('/')
}}"
>
<button class="img-logo-container"><img src="media/logo.png" alt="logo" /></button>
<p class="logo-text">Wasserski-Erfurt</p>
<button class="img-logo-container"><img src="/media/logo.svg" alt="logo" /></button>
<div class="logo-text">
<p id="upper">ALL KIDS</p>
<p id="lower">SO GÜNSTIG WIE NACHHALTIG</p>
</div>
</button>
<ul class="menuitem-container">
{#if $navigation?.elemente}
{#each $navigation.elemente as site, i (i)}
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<li
class="menu-item"
on:mousedown="{() => {
if (site.endpoint) {
let element = document.getElementById('submenu-container')
element.style.height = '0vh'
element.classList.remove('show-submenu')
changeStateOfSite(false)
navigate(`${$sites[site.seite].path}`)
if (element) {
element.style.height = '0vh'
element.classList.remove('show-submenu')
changeStateOfSite(false)
navigate(`${$sites[site.seite || ''].path}`)
}
}
}}"
on:mouseenter|stopPropagation="{(e) => {
@@ -86,8 +98,10 @@
let elements = document.getElementsByClassName('select-menu')
Array.from(elements).forEach((e) => e.classList.remove('select-menu'))
let element = document.getElementById('submenu-container')
element.style.height = '0vh'
element.classList.remove('show-submenu')
if (element) {
element.style.height = '0vh'
element.classList.remove('show-submenu')
}
changeStateOfSite(false)
}, 500)
}
@@ -103,6 +117,7 @@
</ul>
</ul>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
class="submenu-container"
id="submenu-container"
@@ -117,6 +132,7 @@
<div class="inner-container">
{#each $navigation?.elemente as submenu, i (i * 10)}
{#if !submenu?.endpoint}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
on:mouseover|stopPropagation
class="innersubmenu-container"
@@ -133,16 +149,17 @@
/>
</div>
<ul class="sub-menu">
{#each submenu?.elemente as submenu_point, i (i)}
{#each submenu?.elemente || [] as submenu_point, i (i)}
<li>
<button
class="submenu-item"
on:click="{() => {
let element = document.getElementById('submenu-container')
if (!element) return
element.style.height = '0vh'
element.classList.remove('show-submenu')
changeStateOfSite(false)
navigate(`${$sites[submenu_point.seite]?.path}`)
navigate(`${$sites[submenu_point.seite || '']?.path}`)
}}">{submenu_point?.name}</button
>
</li>
@@ -180,6 +197,18 @@
display: flex;
align-items: center;
.logo-text {
p {
white-space: nowrap;
text-align: left;
}
& > #upper {
font-family: "Orbitron" !important;
font-size: 30px;
font-weight: 700;
}
& > #lower {
font-size: 13px;
}
font-weight: bold;
font-size: 1.2rem;
padding-left: 10px;
@@ -214,11 +243,11 @@
align-items: center;
cursor: pointer;
&:hover {
background-color: @hover-color;
background-color: var(--hover-color);
}
}
.select-menu {
background-color: @hover-color;
background-color: var(--hover-color);
}
}
}
@@ -229,7 +258,7 @@
overflow: hidden;
width: 100vw;
z-index: 2000;
background-color: rgba(0, 0, 0, 0.854);
background-color: var(--opposite-bg-color-80);
opacity: 0;
.inner-container {
width: 100%;
@@ -242,7 +271,7 @@
opacity: 0;
position: absolute;
visibility: hidden;
background-color: rgb(255, 255, 255);
background-color: var(--background-color);
display: flex;
justify-content: center;
.submenu-most-inner-container {
@@ -266,7 +295,7 @@
width: 100%;
text-align: start;
&:hover {
border-bottom: 1px solid rgba(24, 24, 24, 0.795);
border-bottom: 1px solid var(--opposite-bg-color-80);
}
button {
padding: 10px 0px;

View File

@@ -6,7 +6,7 @@
let images: HTMLImageElement[] = []
function changeStateOfSite(menuOn: boolean) {
let element = document.getElementById("menu")
let element = document.getElementById("menu") as HTMLElement
element.classList.toggle("show-menu")
let body = document.body
if (menuOn) {
@@ -26,7 +26,7 @@
}
}
function imageSlide(images) {
function imageSlide(images: HTMLImageElement[]) {
console.log(images)
let currentImage = 0
images[0].classList.add("show-img")
@@ -39,12 +39,15 @@
return () => clearInterval(interval)
}
function pushImages(node) {
function pushImages(node: HTMLImageElement) {
images[0] = node
}
$: {
if (images.length != 0) imageSlide(document.getElementsByClassName("img-menu"))
const images = Array.from(document.getElementsByClassName("img-menu")) as HTMLImageElement[]
if (images.length !== 0) {
imageSlide(images)
}
}
</script>
@@ -54,18 +57,19 @@
class="logo-container"
on:click="{() => {
navigate('/')
let element = document.getElementById('menu')
changeStateOfSite(element.classList.contains('show-menu'))
}}"
>
<button class="img-logo-container"><img src="media/logo.png" alt="logo" /></button>
<p class="logo-text">Wasserski-Erfurt</p>
<button class="img-logo-container"><img src="/media/logo.svg" alt="logo" /></button>
<div class="logo-text">
<p id="upper">ALL KIDS</p>
<p id="lower">SO GÜNSTIG WIE NACHHALTIG</p>
</div>
</button>
<button
class="button-three"
on:click="{(e) => {
let element = document.getElementById('menu')
changeStateOfSite(element.classList.contains('show-menu'))
if (element) changeStateOfSite(element.classList.contains('show-menu'))
}}"
aria-controls="primary-navigation"
aria-expanded="false"
@@ -87,22 +91,27 @@
<div class="inner-container">
<div class="higher-absolute">
{#each $navigation.elemente as link, i (i)}
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<li
class="menu"
on:mousedown|stopPropagation="{(e) => {
if (link.endpoint) {
navigate(`${$sites[link.seite]?.path}`)
navigate(`${$sites[link.seite ?? '']?.path}`)
let element = document.getElementById('menu')
changeStateOfSite(element.classList.contains('show-menu'))
if (element) changeStateOfSite(element.classList.contains('show-menu'))
return
}
let element = e.currentTarget
element.classList.toggle('active')
let chevronContainer = document.getElementById('chevron-' + i)
chevronContainer.src =
chevronContainer.src.split('/')?.pop() == 'chevron-down.png'
? 'media/chevron-up.png'
: 'media/chevron-down.png'
if (element) {
element.classList.toggle('active')
let chevronContainer = document.getElementById('chevron-' + i)
if (chevronContainer)
// @ts-ignore
chevronContainer.src = // @ts-ignore
chevronContainer.src.split('/')?.pop() == 'chevron-down.png'
? 'media/chevron-up.png'
: 'media/chevron-down.png'
}
}}"
>
<div class="menu-point">
@@ -114,13 +123,14 @@
</div>
{#if !link?.endpoint}
<ul class="submenu">
{#each link.elemente as submenu, i (i)}
{#each link.elemente ?? [] as submenu, i (i)}
<li>
<button
on:mousedown="{(e) => {
navigate(`${$sites[submenu.seite]?.path}`)
navigate(`${$sites[submenu.seite ?? '']?.path}`)
let element = document.getElementById('menu')
changeStateOfSite(element.classList.contains('show-menu'))
if (element)
changeStateOfSite(element.classList.contains('show-menu'))
}}">{submenu.name}</button
>
</li>
@@ -131,20 +141,7 @@
{/each}
<button class="socials">
<a target="_blank" href="https://www.instagram.com/wasserski_erfurt/">
<svg
width="36"
height="36"
viewBox="0 0 36 36"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.7 3h12.6c4.8 0 8.7 3.9 8.7 8.7v12.6a8.7 8.7 0 0 1-8.7 8.7H11.7C6.9 33 3 29.1 3 24.3V11.7A8.7 8.7 0 0 1 11.7 3zm-.3 3A5.4 5.4 0 0 0 6 11.4v13.2c0 2.985 2.415 5.4 5.4 5.4h13.2a5.4 5.4 0 0 0 5.4-5.4V11.4C30 8.415 27.585 6 24.6 6H11.4zm14.475 2.25a1.875 1.875 0 1 1 0 3.75 1.875 1.875 0 0 1 0-3.75zM18 10.5a7.5 7.5 0 1 1 0 15 7.5 7.5 0 0 1 0-15zm0 3a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9z"
fill="#fff"></path>
</svg>
</a>
<a target="_blank" href="https://www.facebook.com/wasserskierfurt/">
<a target="_blank" href="https://www.facebook.com/allkids.erfurt/">
<svg
width="36"
height="36"
@@ -200,7 +197,8 @@
position: relative;
width: 100%;
height: 100vh;
background-color: white;
background-color: var(--background-color);
ul {
.header {
padding: 0px min(4.5vw, 100px);
@@ -209,7 +207,7 @@
justify-content: space-between;
height: 105px;
.button-three {
--button-color: #333;
--button-color: var(--normal-font-color);
overflow: hidden;
background: transparent;
}
@@ -234,14 +232,25 @@
}
.logo-container {
height: 50px;
height: 38px;
display: flex;
align-items: center;
.logo-text {
p {
white-space: nowrap;
text-align: left;
}
& > #upper {
font-family: "Orbitron" !important;
font-size: 24px;
font-weight: 700;
}
& > #lower {
font-size: 10px;
}
font-weight: bold;
font-size: 1.2rem;
padding-left: 10px;
color: #333;
}
.img-logo-container {
height: 100%;
@@ -282,7 +291,7 @@
}
}
.menu-container {
background-color: white;
background-color: var(--background-color);
position: absolute;
z-index: 2000;
opacity: 0;
@@ -304,18 +313,18 @@
width: 100%;
left: 0px;
padding: 0px min(4.5vw, 100px);
background-color: white;
background-color: var(--background-color);
border-radius: 0px 0px 10px 10px;
}
.socials {
width: 100%;
background-color: @link-font-color;
background-color: var(--link-font-color);
height: 50px;
border-radius: 20px;
color: white;
color: var(--background-color);
}
.active {
background-color: rgba(128, 128, 128, 0.153) !important;
background-color: var(--normal-font-color-12) !important;
.submenu {
visibility: visible;
max-height: 250px;

View File

@@ -0,0 +1,240 @@
<script lang="ts">
import { sites } from "../../stores"
import { register } from "swiper/element/bundle"
import { onMount } from "svelte"
import { navigate } from "svelte-routing"
let teasers = Object.values($sites)?.map((page) => ({ teaser: page.teaser, path: page.path }))
register(false)
let swiper: any
function handleMouseOver() {}
function handleMouseOut() {}
onMount(async () => {
if (swiper !== undefined) {
const response = await fetch("/dist/index.css")
const cssText = await response.text()
const params = {
injectStyles: [cssText],
}
Object.assign(swiper, params)
console.log(swiper.getElementsByClassName("swiper-button-prev"), "test", swiper)
swiper.initialize()
// Add the 'active' class to the h1 of the first slide
const firstSlideH1 = document.querySelector(".swiper-slide-active .titles h1")
if (firstSlideH1) {
firstSlideH1.classList.add("active")
}
}
})
function handleSlideChange() {
document.querySelectorAll(".titles h1").forEach((h1) => {
h1.classList.remove("active")
})
setTimeout(() => {
const activeSlideUnderline = document.querySelector(".swiper-slide-active .titles h1")
if (activeSlideUnderline) {
activeSlideUnderline.classList.add("active")
}
}, 600)
}
let teaser = teasers[0]
</script>
{#if teaser}
<div class="container" id="HP">
<!-- svelte-ignore a11y-no-static-element-interactions -->
<swiper-container
bind:this="{swiper}"
slides-per-view="1"
loop="{true}"
direction="horizontal"
effect="slide"
navigation="{true}"
init="{false}"
autoplay="{{
delay: 4000, // 5000ms = 5s
pauseOnMouseEnter: true,
}}"
speed="600"
on:focus
on:blur
on:slidechange="{() => handleSlideChange()}"
on:mouseenter="{() => handleMouseOver()}"
on:mouseleave="{() => handleMouseOut()}"
class="relative"
>
{#each teasers as teaser}
{#if teaser?.teaser?.showTeaser}
<swiper-slide class="relative">
<div class="inner-container">
<div class="titles">
<h2>{teaser?.teaser?.subTitle}</h2>
<h1>
{teaser?.teaser?.teaserTitle}
<div class="underline"></div>
</h1>
</div>
<div class="description">
<div class="placeholder"></div>
<div
style=" display: flex;
flex-direction: column;
align-items: start;
gap: 20px;"
>
<div style="text-align: left;">
<p>{@html teaser?.teaser?.teaserDescription}</p>
</div>
<button
on:click="{() => navigate(teaser.path)}"
style="
font-weight: bold;
color: var(--link-font-color);
width: fit-content;
border-top: 3px solid var(--link-font-color);
margin-top: 3rem;
">MEHR</button
>
</div>
<div class="placeholder"></div>
</div>
</div>
</swiper-slide>
{/if}
{/each}
</swiper-container>
</div>
{/if}
<style lang="less" global>
@import "../../assets/css/variables.less";
@import "swiper/swiper-bundle.min.css";
@import "swiper/modules/effect-fade/effect-fade";
@import "swiper/modules/navigation/navigation";
@import "swiper/modules/pagination/pagination";
@import "../../assets/css/SwiperStylesHP.less";
.container#HP {
padding: 20px 0px 150px 0px;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
swiper-container {
max-width: 90vw;
width: 1800px;
}
.inner-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 20px;
@media @tablet {
align-items: center;
gap: initial;
}
width: 100%;
height: fit-content;
.titles {
padding: 0 5%;
font-weight: 500;
h1 {
font-size: 2rem;
padding: 10px 0px 0px 0px;
@media @tablet {
padding: 20px 0px;
}
margin: 10px 0px 20px 0px;
line-height: 1;
font-weight: 500;
position: relative;
}
h2 {
font-size: 0.9rem !important;
@media @tablet {
font-size: 1.6rem !important;
}
line-height: 1;
font-weight: 500;
}
}
.description {
display: flex;
flex-direction: row;
& > div {
flex: 0 0 5%;
min-width: 0px;
}
& > div:nth-child(2) {
flex: 0 0 90%;
min-width: 0px;
}
}
@media @tablet {
.titles {
font-weight: 500;
h1 {
font-size: 3.5rem;
padding: 20px 20px;
margin: 20px 0px 40px 0px;
font-weight: 500;
}
h2 {
font-size: 1.3rem;
}
font-weight: 500;
}
.description {
display: flex;
flex-direction: row;
& > div {
flex: 0 0 25%;
min-width: 0px;
}
& > div:nth-child(2) {
flex: 0 0 50%;
min-width: 0px;
}
}
}
@media @desktop {
.titles {
font-weight: 500;
h1 {
font-size: 5rem;
padding: 20px 0px;
margin: 20px 0px 40px 0px;
font-weight: 500;
}
h2 {
font-size: 1.6rem;
font-weight: 500;
}
}
.description {
display: flex;
flex-direction: row;
& > div {
flex: 0 0 33.33%;
min-width: 0px;
}
}
}
}
}
</style>

View File

@@ -4,7 +4,7 @@
let isExpanded = false
let currentIndex = 0
let interval
let interval: NodeJS.Timer
let img: HTMLImageElement
function toggleBanner() {
@@ -74,7 +74,7 @@
.toggle {
position: absolute;
left: 50%;
background-color: @banner-color;
background-color: var(--banner-color);
transform: translate(-50%, -100%);
border-radius: 10px;
}
@@ -107,7 +107,7 @@
bottom: 0;
left: 0;
right: 0;
background-color: @banner-color;
background-color: var(--banner-color);
cursor: pointer;
transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
img {
@@ -115,8 +115,6 @@
}
}
.banner.expanded {
}
.banner-container {
width: 100%;
height: 100%;
@@ -124,13 +122,13 @@
display: flex;
justify-content: space-between;
position: relative;
color: white;
color: var(--background-color);
.toggle {
padding: 10px;
}
.banner-text {
color: white;
color: var(--background-color);
transition: opacity 0.3s ease-in-out;
pointer-events: none;
opacity: 0;

View File

@@ -0,0 +1,43 @@
<script lang="ts">
export let col: Column
import inView from "../../functions/observer"
let visible = false
import { fade } from "svelte/transition"
</script>
<div class="boxList">
{#each col.boxList.boxes as name, i}
{#key visible}
<div
class="box"
use:inView="{{ threshold: 0 }}"
on:enter="{() => {
visible = true
}}"
in:fade="{{ duration: 500, delay: 100 + 80 * (i + 1) }}"
>
{name.name}
</div>{/key}
{/each}
</div>
<style lang="less">
@import "../../assets/css/variables.less";
.boxList {
display: flex;
flex-wrap: wrap;
gap: 20px;
.box {
padding: 5px 10px;
background-color: var(--opposite-bg-color-80);
color: var(--background-color);
font-weight: bold;
cursor: pointer;
&:hover {
background-color: var(--hover-color);
color: var(--opposite-bg-color-80);
}
}
}
</style>

View File

@@ -1,10 +1,12 @@
<script lang="ts">
import FormLabelNumberBlock from "./formLabelNumberBlock.svelte"
import type { Writable } from "svelte/store"
export let formRow: FormRow
export let index: number
export let formValues
function getSortedFields(column: FormColumn) {
export let formValues: Writable<FormValues>
/* function getSortedFields(column: FormColumn) {
const fields = [
...(column.text.length ? [{ text: column.text, type: "text", order: column.textfieldOrder ?? 3 }] : []),
...(column.showTimes ? [{ type: "times", order: column.timesfieldOrder ?? 3, times: column.times }] : []),
@@ -13,11 +15,11 @@
: []),
]
return fields.sort((a, b) => a.order - b.order)
}
}*/
//formRow.columns = formRow.columns.map((e) => getSortedFields(e))
function removeInvalid(e) {
let element = e.currentTarget
element.classList.remove("invalid")
function removeInvalid(e: Event) {
let element = e.currentTarget as HTMLElement
if (element) element.classList.remove("invalid")
}
</script>
@@ -46,7 +48,7 @@
on:change="{removeInvalid}"
>
<option value="" disabled selected>Bitte Uhrzeit wählen</option>
{#each column?.times as time}
{#each column?.times || [] as time}
<option value="{time?.timeFrom}-{time?.timeTo}">
{time?.timeFrom} - {time?.timeTo}
</option>
@@ -112,7 +114,7 @@
</label>
{/if}
{#each column.text as textField, textFieldIndex}
{#each column.text || [] as textField, textFieldIndex}
{#if textField?.textArea}
<label bind:this="{$formValues[`textarea_Nachricht_label`]}">
<textarea

View File

@@ -1,10 +1,11 @@
<script lang="ts">
export let column
export let formValues
export let rowIndex
let blockContainer
import type { Writable } from "svelte/store"
export let column: FormColumn
export let formValues: Writable<FormValues>
export let rowIndex: number
let blockContainer: HTMLDivElement
$formValues["blockGroups"] = new Set(column.labelNumber.map((e) => e.group))
console.log($formValues["blockGroups"])
</script>
<div class="blockContainer" bind:this="{blockContainer}">

View File

@@ -1,15 +1,16 @@
<script lang="ts">
import FormLabelNumberBlock from "./formLabelNumberBlock.svelte"
import type { Writable } from "svelte/store"
export let formRow: FormRow
export let formValues
export let index
function removeInvalid(e) {
let element = e.currentTarget
element.classList.remove("invalid")
export let formValues: Writable<FormValues>
export let index: number
function removeInvalid(e: Event) {
let element = e.currentTarget as HTMLElement
if (element) element.classList.remove("invalid")
}
function getPosition(column, pos, i = 0) {
function getPosition(column: FormColumn, pos: number, i = 0) {
let position = 0
if (pos == 0) return
if (column.showLabelNumber) position++
@@ -53,7 +54,7 @@
on:change="{removeInvalid}"
>
<option value="" disabled selected>Bitte Uhrzeit wählen</option>
{#each column?.times as time}
{#each column?.times ?? [] as time}
<option value="{time?.timeFrom}-{time?.timeTo}">
{time?.timeFrom} - {time?.timeTo}
</option>
@@ -126,7 +127,7 @@
</div>
{/if}
{#each column.text as textField, textFieldIndex}
{#each column.text ?? [] as textField, textFieldIndex}
<div class="column-{columnIndex} position-{getPosition(column, 5 + textFieldIndex, textFieldIndex)}">
{#if textField?.textArea}
<label bind:this="{$formValues[`textarea_Nachricht_label`]}">

View File

@@ -2,7 +2,7 @@
import { navigate } from "svelte-routing"
import { fly } from "svelte/transition"
export let col: Column
export let siteId
export let siteId: string
import { apiBaseURL } from "../../../config"
import inView from "../../functions/observer"
let visible = false
@@ -19,7 +19,7 @@
}}"
>
{#key visible}
{#each col.iconBoard as icon, i (i)}
{#each col.iconBoard ?? [] as icon, i (i)}
<div
class="img-container"
id="{'img-container' + i}"
@@ -67,7 +67,7 @@
min-width: 25%;
.subText {
text-align: center;
color: @heading-font-color;
color: var(--heading-font-color);
}
@media @mobile {
width: 50%;
@@ -77,17 +77,5 @@
}
}
}
@media @tablet {
main {
margin-top: 300px !important;
}
.background-container {
margin-top: -180px !important;
}
.title {
font-size: 3rem !important;
}
}
}
</style>

View File

@@ -0,0 +1,75 @@
<script lang="ts">
import { apiBaseURL } from "../../../config"
import { fly } from "svelte/transition"
import inView from "../../functions/observer"
let visible = false
let node
export let col: Column
export let pageId: string
export let i: number
</script>
{#key visible}
<div
class="infoBoard"
bind:this="{node}"
use:inView="{{ threshold: 0 }}"
on:enter="{() => {
visible = true
}}"
in:fly="{{ duration: 600, delay: 100 + 100 * (i + 1), x: 300 + i * 200, opacity: 0 }}"
>
<div class="header">
<div class="icon">
<svg
id="mySvgObject{i}"
fill="var(--link-font-color)"
data-src="{`${apiBaseURL}content/${pageId}/${col.iconInfoBoard.icon?.src}`}"></svg>
</div>
<div class="title">
{col.iconInfoBoard.title}
<div></div>
</div>
</div>
<div class="content">
{@html col.iconInfoBoard.text}
</div>
</div>
{/key}
<style lang="less">
@import "../../assets/css/variables.less";
.infoBoard {
display: flex;
flex-direction: column;
padding: 15px;
gap: 40px;
.header {
display: flex;
align-items: center;
gap: 20px;
.icon {
width: 64px;
height: 64px;
svg {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.title {
font-size: 1.5rem;
display: flex;
flex-direction: column;
color: var(--link-font-color);
div {
border-bottom: 1px solid var(--normal-font-color);
width: 50px;
}
}
}
.content {
text-align: left;
}
}
</style>

View File

@@ -1,14 +1,13 @@
<script lang="ts">
import { onMount } from "svelte"
import { register } from "swiper/element/bundle"
import Pagebuilder from "./Pagebuilder.svelte"
import { apiBaseURL } from "../../../config"
export let siteId
export let siteImages
export let siteId: string
export let siteImages: ImageSlider[]
register(false)
let swiper
let swiper: any
onMount(async () => {
if (swiper !== undefined) {
@@ -27,7 +26,7 @@
</script>
{#if siteImages.length > 1}
<div class="flex">
<div class="flex images">
<swiper-container
bind:this="{swiper}"
slides-per-view="1"
@@ -42,7 +41,7 @@
class="relative"
>
{#each siteImages as image, i (i)}
<swiper-slide class="relative">
<swiper-slide class="relative" id="image">
<div class="image-container">
<img
src="{`${apiBaseURL}content/${siteId}/${image.image?.src}?filter=${
@@ -71,11 +70,13 @@
@import "swiper/modules/pagination/pagination.less";
@import "../../assets/css/variables.less";
@import "../../assets/css/swiperStyles.less";
swiper-container {
height: auto;
width: 100%;
max-width: 100vw;
}
swiper-slide {
swiper-slide#image {
width: 100% !important;
}
.flex {

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import { navigate } from "svelte-routing"
import { fly } from "svelte/transition"
export let col: Column
export let siteId
export let i
export let siteId: string
export let i: number
import { apiBaseURL } from "../../../config"
import inView from "../../functions/observer"
let visible
let visible = false
let node
</script>
@@ -36,9 +36,11 @@
<div class="links">
{#if col?.links}
{#each col?.links as link}
<button on:click="{() => navigate(link?.site)}">
<img src="media/arrow-right.svg" alt="arrow" />{link?.name}
</button>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"
fill="var(--link-font-color)"></path>
</svg>
{/each}
{/if}
</div>
@@ -70,8 +72,7 @@
font-weight: 700;
padding-bottom: 1.2rem;
}
.description-container {
}
.links {
margin-top: 25px;
img {
@@ -81,7 +82,7 @@
button {
display: flex;
align-items: center;
color: @link-font-color;
color: var(--link-font-color);
font-weight: 600;
margin: 10px 0px;
}

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { fly } from "svelte/transition"
export let col: Column
export let siteId
export let siteId: string
import { apiBaseURL } from "../../../config"
</script>
@@ -15,7 +15,7 @@
/>
</div>
<div class="inscription" in:fly="{{ duration: 1000, delay: 500, y: 50, opacity: 0 }}">
{col.inscription}
{col.inscription || ""}
</div>
</div>
@@ -44,7 +44,7 @@
margin-right: 35px;
font-size: 1.7rem;
font-weight: 700;
color: white;
color: var(--heading-font-color);
}
@media @tablet {
.inscription {

View File

@@ -1,7 +1,6 @@
<script lang="ts">
export let row: Row
export let rows: Row[]
import { apiBaseURL } from "../../../config"
import IconBoard from "./iconBoard.svelte"
import Image from "./image.svelte"
import InfoBoard from "./infoBoard.svelte"
@@ -13,24 +12,23 @@
import { writable } from "svelte/store"
import { validateFields } from "../../functions/validateFields"
import { sendForm } from "../../functions/sendForm"
import VideoSwitch from "../videoSwitch.svelte"
import GoogleMaps from "../googleMaps.svelte"
import Video from "./video.svelte"
import { navigate } from "svelte-routing"
import { onMount } from "svelte"
export let siteId
export let rowNr
import IconInfoBoard from "./iconInfoBoard.svelte"
import Boxlist from "./boxlist.svelte"
import ProductPreview from "./productPreview.svelte"
export let siteId: string
export let rowNr: number
let formSend = false
let formValues = writable({})
function getRowClass(row) {
let formValues = writable<FormValues>({})
function getRowClass(row: Row) {
if (row.maxWidth || row.column.some((col) => col.iconBackgroundImage)) return "max-width"
return row.column.some((col) => col.contentType === "mainPicture" || col.contentType == "video")
? "max-width"
: "small-max-width"
return row.column.some((col) => col.contentType === "mainPicture") ? "max-width" : "small-max-width"
}
function submitForm(e) {
function submitForm() {
const values = Object.entries($formValues).map((entry) => {
return [
entry[0],
@@ -41,114 +39,75 @@
})
const fields = values.filter((entry) => !entry[0].includes("label"))
console.log(fields)
const validation = validateFields([...fields])
if (validation.length) {
validation.forEach((error) => {
// @ts-ignore
if (error[0].includes("block")) {
// @ts-ignore
error[1]()
} else {
// @ts-ignore
$formValues[error[1]].classList.add("invalid")
const label = $formValues[`${error[1]}_label`]
const errorElement = document.createElement("div")
errorElement.className = "error-message"
errorElement.textContent = error[0]
errorElement.textContent = error[0] as string
label?.appendChild(errorElement)
}
})
} else {
const formObj = {}
const formObj: any = {}
fields.forEach((entry) => {
if (Array.isArray(entry[1]) && entry[1].length == 4) {
// @ts-ignore
if (entry[1][0]) formObj[entry[0]] = entry[1]
} else {
if (!entry[1][0] && !entry[1][1]) return
// @ts-ignore
formObj[entry[0]] = entry[1][0]
}
})
console.log(fields, formObj)
let form
let form: any
row.column.forEach((col) => {
if (col.contentType == "form") form = col
})
formObj["formRows"] = form.formRows.map((r) => r.rowName)
if (!form) return
formObj["formRows"] = form.formRows.map((r: FormRow) => r.rowName)
formObj["formTitle"] = form.formEmailTitle
formSend = true
const hny = document.getElementById("hny")
formObj["honey"] = hny.checked
const hny = document.getElementById("hny") as HTMLInputElement
if (hny) formObj["honey"] = hny.checked
sendForm(formObj)
}
}
let videoElement
onMount(() => {
if (videoElement) {
var source = document.createElement("source")
if (window.innerWidth <= 767) {
source.src = "media/wasser_mobile.webm"
} else {
source.src = "media/wasser_desktop.webm"
}
videoElement.appendChild(source)
videoElement.load()
}
const handleResize = () => {
innerWidth = window.innerWidth
if (
(window.innerWidth >= 768 && innerWidthStore < 768) ||
(window.innerWidth < 768 && innerWidthStore >= 768)
) {
innerWidthStore = window.innerWidth
window.location.reload()
}
}
window.addEventListener("resize", handleResize)
// Cleanup function
return () => {
window.removeEventListener("resize", handleResize)
}
})
let innerWidth = window.innerWidth
let innerWidthStore = window.innerWidth
</script>
<main class="row" name="{row.title}" class:max-width="{getRowClass(row) === 'max-width'}" id="{`RowNr` + rowNr}">
{#if row?.iconBackgroundImage}
<div class="virtual-container">
<div class="wavebackground-container">
{#if row?.iconBackgroundTitle} <div class="title">Highlights des Sees</div>{/if}
<video class="video-background" autoplay loop muted playsinline bind:this="{videoElement}"> </video>
</div>
</div>
{#if row.title}
<h3 class="row-title" class:no-margin="{rowNr == 0}">{row?.title || ""}</h3>
{/if}
{#if row.iconBackgroundImage}
<div class="wave-placeholder"></div>
{/if}
{#if row.title || row.iconBackgroundImage}
<h3 class="row-title" class:no-margin="{rowNr == 0 || row.iconBackgroundImage}">{row?.title || ""}</h3>
{/if}
<div class:no-gap="{row.noGap}">
{#each row.column as col, i}
<div class:no-gap="{row.noGap}" class:wrapAfterTwo="{row.column.length >= 4}">
{#each row.column || [] as col, i}
{#if col.contentType == "mainPicture"}
<MainPicture col="{col}" siteId="{siteId}" />
{:else if col.contentType == "text"}
<TextContent rows="{rows}" col="{col}" />
{:else if col.contentType == "infoBoard"}
<InfoBoard siteId="{siteId}" col="{col}" i="{i}" />
{:else if col.contentType == "iconInfoBoard"}
<IconInfoBoard pageId="{siteId}" col="{col}" i="{i}" />
{:else if col.contentType == "boxlist"}
<Boxlist col="{col}" />
{:else if col.contentType == "iconBoard"}
<IconBoard col="{col}" siteId="{siteId}" i="{i}" />
<IconBoard col="{col}" siteId="{siteId}" />
{:else if col.contentType == "image"}
<Image siteImages="{col.imageSlider}" siteId="{siteId}" />
{:else if col.contentType == "table"}
<Table col="{col}" rows="{rows}" />
{:else if col.contentType == "videos"}
<VideoSwitch col="{col}" siteId="{siteId}" />
{:else if col.contentType == "video"}
<Video col="{col}" siteId="{siteId}" />
{:else if col.contentType == "productPreview"}
<ProductPreview col="{col}" siteId="{siteId}" />
{:else if col.contentType == "googleMaps"}{#if col.showGoogleMaps}
<GoogleMaps />
{/if}
@@ -163,10 +122,10 @@
class="form-rows"
on:submit="{(e) => {
e.preventDefault()
submitForm(e)
submitForm()
}}"
>
{#each col.formRows as formRow, i}
{#each col.formRows ?? [] as formRow, i}
{#if innerWidth < 768}
<MobileForm formRow="{formRow}" formValues="{formValues}" index="{i}" />
{:else}
@@ -228,67 +187,10 @@
margin: 5px 0px;
box-shadow: 0 0 25px 10px rgba(0, 0, 0, 0.05);
}
.virtual-container {
display: flex;
padding-top: 90px;
max-width: @body-small-maxwidth;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
width: 100%;
.wavebackground-container {
position: absolute;
overflow: hidden;
display: flex;
justify-content: center;
width: 100vw;
left: 0px;
height: 450px;
z-index: -1;
.video-background {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
-webkit-mask-image: url("../../../../media/welle.svg");
mask-image: url("../../../../media/welle.svg");
-webkit-mask-size: 30px;
mask-size: 30px;
-webkit-mask-repeat: repeat-x;
mask-repeat: repeat-x;
z-index: -1;
}
@media @mobile {
.title {
margin-top: 40px;
}
}
@media @tablet {
.title {
margin-top: 75px;
}
}
.title {
font-size: 2rem;
color: white;
font-weight: bold;
}
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to top, rgb(255, 255, 255), rgba(255, 255, 255, 0.144));
z-index: 10;
}
}
}
.success-message {
h1 {
color: @banner-color;
color: var(--banner-color);
font-size: 36px;
margin-top: 50px;
}
@@ -314,15 +216,12 @@
border-color: red !important;
}
li {
}
.row-title {
font-size: 1.6rem;
font-weight: bold;
line-height: normal;
width: 100%;
color: @heading-font-color;
color: var(--heading-font-color);
@media @mobile {
margin: 3.2rem 1.5vw 1.6rem;
}
@@ -361,6 +260,7 @@
input[type="number"] {
-moz-appearance: textfield;
appearance: textfield;
}
ul {
@@ -374,7 +274,7 @@
li::before {
content: ""; /* Add an empty content */
background-image: url("../../../../media/arrow-right.svg"); /* Replace this with the path to your SVG file */
background-image: url("../../../../media/arrow-right.svg");
background-size: contain;
background-repeat: no-repeat;
position: absolute;
@@ -427,13 +327,13 @@
}
.submit-request {
flex: 1;
box-shadow: 0 0 25px 10px rgba(0, 0, 0, 0.05);
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
width: 100%;
display: flex;
align-items: center;
justify-content: start;
background-color: @heading-font-color;
color: white;
background-color: var(--heading-font-color);
color: var(--background-color);
padding: 10px 20px;
}
}
@@ -491,7 +391,7 @@
p {
margin-bottom: 0.5rem;
color: #777;
color: var(--hover-color);
}
input,
@@ -500,10 +400,10 @@
.data-protection {
padding: 10px 20px;
border: 0px solid black;
border-bottom: 3px solid @heading-font-color;
border-bottom: 3px solid var(--heading-font-color);
outline: 0px solid black;
background-color: white;
background-color: var(--background-color);
resize: none;
}
@@ -525,12 +425,12 @@
select {
padding: 10px 20px;
border: 0;
border-bottom: 3px solid @heading-font-color;
border-bottom: 3px solid var(--heading-font-color);
outline: none;
}
select:focus {
border-bottom-color: @heading-font-color;
border-bottom-color: var(--heading-font-color);
}
#time-select {
@@ -542,15 +442,13 @@
option {
padding: 10px 20px;
background-color: white;
background-color: var(--background-color);
}
}
@media @mobile {
.date {
width: 100vw !important;
}
.form-cols {
}
}
@media @tablet {
.date {
@@ -585,6 +483,10 @@
& > div {
gap: 40px;
}
& > div.wrapAfterTwo {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
@media @desktop {
.no-gap {
@@ -593,7 +495,9 @@
.row-title {
font-size: 2.5rem !important;
}
& > div {
& > div,
& > div.wrapAfterTwo {
display: flex;
flex-direction: row;
align-items: start;
justify-content: center;

View File

@@ -0,0 +1,120 @@
<script lang="ts">
export let col: Column
export let siteId: string
import { register } from "swiper/element/bundle"
import { apiBaseURL } from "../../../config"
import { onMount } from "svelte"
register(false)
let swiper: any
console.log("TST RENDERED")
onMount(async () => {
if (swiper) {
const response = await fetch("/dist/index.css")
const cssText = await response.text()
const params = {
injectStyles: [cssText],
}
if (swiper) {
Object.assign(swiper, params)
swiper.initialize()
}
}
})
</script>
<main id="products">
<swiper-container
bind:this="{swiper}"
slides-per-view="3"
loop="{true}"
direction="horizontal"
effect="coverflow"
init="{false}"
speed="400"
class="relative"
grab-cursor="{true}"
scrollbar-hide="false"
on:focus
on:blur
autoplay="{{
delay: 1000, // 5000ms = 5s
pauseOnMouseEnter: true,
}}"
>
{#each col.productPreview as product}
<swiper-slide class="relative" id="product">
<div class="product">
<div class="img-container">
<img
src="{`${apiBaseURL}content/${siteId}/${product.image?.src}?filter=${
window.innerWidth > 500 ? 'xl' : 'm'
}`}"
alt="img"
/>
<div class="price-container">
{product?.price}
</div>
</div>
<div class="title-container">
{@html product?.title}
</div>
<div class="description-container">
{@html product?.text}
</div>
</div>
</swiper-slide>
{/each}
</swiper-container>
</main>
<style lang="less" global>
@import "../../assets/css/variables.less";
@import "swiper/swiper-bundle.min.css";
@import "swiper/modules/effect-fade/effect-fade";
@import "swiper/modules/navigation/navigation";
@import "swiper/modules/pagination/pagination";
@import "../../assets/css/productSwiper.less";
#products {
flex: 1;
display: flex;
justify-content: center;
max-width: @body-small-maxwidth;
.product {
margin: 0px 35px 40px 35px;
.img-container {
flex: 1;
height: 270px;
background-color: var(--background-color);
@media @tablet {
height: 65vw;
}
@media @desktop {
height: 270px;
}
img {
width: 100%;
height: 100%;
object-fit: contain;
padding: 1rem 0px;
}
position: relative;
.price-container {
position: absolute;
bottom: 1rem;
right: 0px;
font-weight: bold;
background-color: var(--background-color);
padding: 9px;
}
}
.title-container {
font-weight: 700;
padding-bottom: 1.2rem;
}
}
}
</style>

View File

@@ -0,0 +1,66 @@
<script>
import { onMount, onDestroy } from "svelte"
// import { rerender } from "../../store"
let showButton = true
const checkScroll = () => {
// Change the visibility of the button based on the scroll position
showButton = window.pageYOffset < 100
}
const jumpDown = () => {
// Jump down by 100vh
window.scrollTo({ top: window.innerHeight, behavior: "smooth" })
}
onMount(() => {
// Attach scroll event listener when component is mounted
window.addEventListener("scroll", checkScroll)
})
onDestroy(() => {
// Remove scroll event listener when component is destroyed
window.removeEventListener("scroll", checkScroll)
})
let force = true
setInterval(() => {
if (location.pathname != "/") {
force = false
} else force = true
}, 1000)
$: {
/* if ($rerender) {
if (location.pathname != "/") {
force = false
} else force = true
}*/
}
</script>
{#if showButton && force}
<button on:click="{jumpDown}" class="jump-down"
><span> SCROLL </span>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m22.723 5.473 1.054 1.054L12 18.305.223 6.527l1.054-1.054L12 16.195 22.723 5.473z"
fill="var(--link-font-color)"></path>
</svg>
</button>
{/if}
<style>
.jump-down {
/* Place your styles here */
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
color: var(--link-font-color);
z-index: 100;
gap: 5px;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
</style>

View File

@@ -0,0 +1,54 @@
<script>
import { onMount, onDestroy } from "svelte"
let showButton = false
const checkScroll = () => {
// Change the visibility of the button based on the scroll position
showButton = window.pageYOffset > 200
}
const scrollToTop = () => {
// Scroll smoothly to the top
window.scrollTo({ top: 0, behavior: "smooth" })
}
onMount(() => {
// Attach scroll event listener when component is mounted
window.addEventListener("scroll", checkScroll)
})
onDestroy(() => {
// Remove scroll event listener when component is destroyed
window.removeEventListener("scroll", checkScroll)
})
</script>
{#if showButton}
<button on:click="{scrollToTop}" class="arrow-up">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z" fill="var(--background-color)"
></path>
</svg></button
>
{/if}
<style lang="less">
@import "../../assets/css/variables.less";
.arrow-up {
position: fixed;
display: flex;
align-items: center;
justify-content: center;
bottom: 10px;
right: 10px;
height: 2rem;
width: 2rem;
border-radius: 50%;
z-index: 1000;
background-color: var(--link-font-color);
svg {
transform-origin: center;
}
}
</style>

View File

@@ -2,7 +2,7 @@
import inView from "../../functions/observer"
import { fly } from "svelte/transition"
export let rows: Row[]
function scrollToRow(name) {
function scrollToRow(name: string) {
const element = document.getElementsByName(name)[0]
if (element) {
element.scrollIntoView({ behavior: "smooth" })
@@ -27,7 +27,10 @@
class="siteRef"
on:click="{() => scrollToRow(row.title)}"
in:fly="{{ duration: 1000, delay: 40 * i, opacity: 0, y: 150 }}"
><img src="media/arrow-bottom-right.svg" alt="arrow" />{row?.title}</button
><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 6.41 6.41 5 17 15.59V9h2v10H9v-2h6.59L5 6.41z" fill="var(--link-font-color)"></path>
</svg>
{row?.title}</button
>
{/if}
{/each}
@@ -41,11 +44,11 @@
button {
display: flex;
align-items: center;
img {
svg {
transform: scale(1.4);
margin: 0.5rem 0.9rem 0.5rem 0rem;
}
color: @link-font-color;
color: var(--link-font-color);
font-weight: 600;
}
}

View File

@@ -19,7 +19,7 @@
>
<h3>{col?.tableFieldHeading ?? ""}</h3>
{#key visible}
{#each col?.table as table, i (table?.title)}
{#each col?.table ?? [] as table, i (table?.title)}
<div class="table" in:fly="{{ duration: 1000, delay: i * 150, y: 130, opacity: 0 }}">
<div class="tableTitle">{table?.title ?? ""}</div>
@@ -89,7 +89,7 @@
font-size: 2rem;
font-weight: bold;
margin: 0rem 0vw 1.6rem 0vw;
color: @heading-font-color;
color: var(--heading-font-color);
}
h5 {

View File

@@ -2,12 +2,12 @@
import { navigate } from "svelte-routing"
export let site: Site
import Image from "./image.svelte"
export let index
export let index: number
</script>
<main class="teaser">
{#if index % 2 == 0 || window.innerWidth < 1023}
<Image siteId="{site?.id}" siteImages="{site?.teaserImages}" />
<Image siteId="{site?.id}" siteImages="{site?.teaserImages || []}" />
{/if}
<div class="content">
<h3>{site?.teaserTitle}</h3>
@@ -15,7 +15,7 @@
<button on:click="{() => navigate(site.path)}">MEHR</button>
</div>
{#if index % 2 == 1 && window.innerWidth > 1023}
<Image siteId="{site?.id}" siteImages="{site?.teaserImages}" />
<Image siteId="{site?.id}" siteImages="{site?.teaserImages || []}" />
{/if}
</main>
@@ -41,13 +41,13 @@
font-size: 2rem;
font-weight: bold;
margin: 0rem 0 1.6rem 0;
color: @heading-font-color;
color: var(--heading-font-color);
}
button {
font-weight: bold;
color: @link-font-color;
color: var(--link-font-color);
width: fit-content;
border-top: 3px solid @link-font-color;
border-top: 3px solid var(--link-font-color);
margin-top: 3rem;
}
}

View File

@@ -6,7 +6,7 @@
</script>
<div class="text-container">
<h3 class:noMargin={!col.textFieldHeading}>{col.textFieldHeading ?? ""}</h3>
<h3 class:noMargin="{!col.textFieldHeading}">{col.textFieldHeading ?? ""}</h3>
{#if col?.textContent}
<div>
{@html col?.textContent}
@@ -15,11 +15,12 @@
{#if col.siteReference}
<SiteRefs rows="{rows}" />
{/if}
<li style="display: none;"></li>
</div>
<style lang="less">
@import "../../assets/css/variables.less";
.noMargin{
.noMargin {
margin: 0px !important;
}
.text-container {
@@ -30,7 +31,7 @@
font-size: 2rem;
font-weight: bold;
margin: 0rem 0vw 1.6rem 0vw;
color: @heading-font-color;
color: var(--heading-font-color);
}
}
@media @mobile {

View File

@@ -1,163 +0,0 @@
<script lang="ts">
import { apiBaseURL } from "../../../config"
import { navigate } from "svelte-routing"
import { fly } from "svelte/transition"
let container
let videoElement
let videoText
let videoWrapper
let cooldown = false
export let col
export let siteId
</script>
<div id="wrapper" class="video-container" bind:this="{container}">
<div class="video-wrapper video-wrapper-big" bind:this="{videoWrapper}">
<div class="text shown" bind:this="{videoText}">
<h2 in:fly="{{ duration: 1000, delay: 500, y: 50, opacity: 0 }}">{col.titleVideo}</h2>
<p in:fly="{{ duration: 1000, delay: 500, y: 50, opacity: 0 }}">
{col.descriptionVideo}
</p>
</div>
<video
autoplay
class="video"
playsinline
src="{`${apiBaseURL}content/${siteId}/${col.video?.src}`}"
loop
alt="video1"
muted
bind:this="{videoElement}"><track kind="captions" /></video
>
</div>
</div>
<style lang="less">
@import "../../assets/css/variables.less";
#wrapper {
width: 100%;
flex: 2;
}
.video-wrapper {
width: 100%;
display: flex;
max-height: min(700px, 55vh);
overflow: hidden;
position: relative;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 10;
}
@media @mobile {
.hidden {
p,
button {
visibility: hidden !important;
opacity: 0;
height: 0px;
margin-top: 0px !important;
transition: opacity 0s;
}
h2 {
margin-bottom: 0px !important;
transform: translateY(50%);
}
}
.shown {
opacity: 1;
visibility: visible;
}
}
@media @desktop {
.hidden {
h2 {
visibility: hidden;
transition: opacity 0s;
}
}
}
.text {
position: absolute;
z-index: 20;
max-width: 85%;
color: rgb(255, 255, 255);
animation-delay: 500ms;
bottom: 35px;
left: 35px;
@media @mobile {
h2 {
font-size: 2.8rem;
font-weight: bold;
line-height: normal;
margin-bottom: 5px;
}
p {
line-height: normal;
}
button {
border-top: 3px solid white;
font-size: 1.4rem;
font-weight: bold;
color: white;
margin-top: 15px;
}
}
@media @desktop {
max-width: 70%;
h2 {
font-size: 2.7rem;
}
p {
}
button {
font-size: 1.5rem;
}
}
}
}
.video {
width: 100%;
min-height: max(35vh, 400px);
height: 100% !important;
object-fit: cover;
}
@media (max-width: 1023px) {
.video-container {
flex-direction: column;
}
.text {
max-width: 90%;
}
video {
height: 100% !important;
min-height: max(45vh, 60vw) !important;
width: auto !important;
min-width: 100%;
object-fit: cover;
object-position: center;
}
.video-wrapper-small,
.video-wrapper-big {
width: 100%;
}
}
</style>

View File

@@ -1,315 +0,0 @@
<script lang="ts">
import { onMount } from "svelte"
import { apiBaseURL } from "../../config"
import { navigate } from "svelte-routing"
import { temperature } from "../stores"
export let siteId
let container
let videoElements = []
let videoTexts = []
let videoWrappers = []
let cooldown = false
export let col
onMount(() => {
container.style.height = videoElements[0].offsetHeight + "px"
Array.from(videoElements).forEach((e) => {
e.style.height = "100%"
})
videoElements[0].play()
videoElements[1].play()
setTimeout(() => {
videoElements[1].pause()
}, 0)
videoWrappers.forEach((videoWrapper) => {
const video = videoWrapper.querySelector(".video")
let eventFunc = (e) => {
if (cooldown) return
let selected = e.currentTarget
cooldown = true
setTimeout(() => {
cooldown = false
}, 502)
let text = selected.querySelector(".text")
videoWrappers.forEach((vw) => {
if (selected == vw) {
vw.classList.add("video-wrapper-big")
vw.classList.remove("video-wrapper-small")
} else {
vw.classList.add("video-wrapper-small")
vw.classList.remove("video-wrapper-big")
}
vw.querySelector(".video").pause()
})
videoTexts.forEach((vt) => {
if (text == vt) {
setTimeout(() => {
vt.classList.add("shown")
vt.classList.remove("hidden")
}, 500)
} else {
vt.classList.add("hidden")
vt.classList.remove("shown")
}
})
video.play()
}
videoWrapper.addEventListener("mousemove", (e) => eventFunc(e))
videoWrapper.addEventListener("click", (e) => eventFunc(e))
})
})
let innerWidth = window.innerWidth
</script>
<div class="video-top-lvl-container">
<div id="wrapper" class="video-container" bind:this="{container}">
<div class="video-wrapper video-wrapper-big" bind:this="{videoWrappers[0]}">
<div class="text shown" bind:this="{videoTexts[0]}">
<h2>{col.videoSwitch[0]?.title}</h2>
<p>
{col.videoSwitch[0]?.description}
</p>
<button
class="link"
on:click="{() => {
navigate(col.videoSwitch[0]?.link)
}}">MEHR</button
>
</div>
<video
class="video"
playsinline
src="{`${apiBaseURL}content/${siteId}/${col.videoSwitch[0].video?.src}`}"
loop
alt="video1"
muted
bind:this="{videoElements[0]}"><track kind="captions" /></video
>
</div>
<div class="video-wrapper video-wrapper-small" bind:this="{videoWrappers[1]}">
<div class="text hidden" bind:this="{videoTexts[1]}">
<h2>{col.videoSwitch[1]?.title}</h2>
<p>
{col.videoSwitch[1]?.description}
</p>
<button
class="link"
on:click="{() => {
navigate(col.videoSwitch[1]?.link)
}}">MEHR</button
>
</div>
<video
class="video"
loop
playsinline
src="{`${apiBaseURL}content/${siteId}/${col.videoSwitch[1].video?.src}`}"
muted
bind:this="{videoElements[1]}"><track kind="captions" /></video
>
</div>
</div>
<div class="icons">
<button class="thermo">
<img src="/media/thermometer.svg" alt="temp" />
{Number($temperature).toFixed(1) || "-"} °C
</button>
</div>
</div>
<style lang="less">
@import "../assets/css/variables.less";
.video-top-lvl-container {
width: 100%;
display: flex;
flex-direction: column;
gap: 40px;
}
.video-container {
display: flex;
width: 100%;
@media @mobile {
gap: 20px;
}
@media @tablet {
gap: 40px;
}
}
.icons {
display: flex;
width: 100%;
@media @mobile {
justify-content: end;
}
@media @tablet {
justify-content: end;
button {
margin: 28px 2rem !important;
}
}
margin-bottom: 60px;
img {
transform: scale(1.5);
margin: 0px 0.4rem;
}
button {
display: flex;
font-weight: bold;
justify-content: center;
font-size: 1rem;
position: relative;
margin: 0 1rem;
}
button::before {
font-weight: 400;
position: absolute;
transform: translateY(-150%);
}
.camera::before {
content: "Webcam";
}
.thermo::before {
content: "Lufttemperatur";
}
.waves::before {
content: "Wassertemperatur";
}
}
.video-wrapper {
overflow: hidden;
position: relative;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
z-index: 10;
}
@media @mobile {
.hidden {
p,
button {
visibility: hidden !important;
opacity: 0;
height: 0px;
margin-top: 0px !important;
transition: opacity 0s;
}
h2 {
margin-bottom: 0px !important;
transform: translateY(50%);
}
}
.shown {
opacity: 1;
visibility: visible;
}
}
@media @desktop {
.hidden {
h2 {
visibility: hidden;
transition: opacity 0s;
}
}
}
.text {
position: absolute;
z-index: 20;
max-width: 85%;
color: rgb(255, 255, 255);
animation-delay: 500ms;
bottom: 35px;
left: 35px;
@media @mobile {
h2 {
font-size: 2.8rem;
font-weight: bold;
line-height: normal;
margin-bottom: 5px;
}
p {
line-height: normal;
}
button {
border-top: 3px solid white;
font-weight: bold;
padding-top: 2px;
color: white;
font-size: 16px;
margin-top: 15px;
}
}
@media @desktop {
max-width: 70%;
h2 {
font-size: 2.7rem;
}
p {
}
button {
font-size: 24px;
}
}
}
}
.video {
width: 100%;
min-height: max(35vh, 400px);
height: auto;
object-fit: cover;
position: absolute;
top: 0;
left: 0;
}
.video-wrapper-big {
flex: 3;
}
.video-wrapper-small {
flex: 1 !important;
}
.video-wrapper-big:hover,
.video-wrapper-small:hover {
flex: 3;
}
@media (max-width: 1023px) {
.video-container {
flex-direction: column;
}
.text {
max-width: 90%;
}
video {
height: 100% !important;
min-height: 75vh !important;
width: auto !important;
min-width: 100%;
object-fit: cover;
object-position: center;
}
.video-wrapper-small,
.video-wrapper-big {
width: 100%;
}
}
</style>

View File

@@ -1,6 +1,6 @@
import { api } from "../../api"
export async function loadBanner(): Promise<Banner[]> {
let banner = await api<any>("banner", {})
return banner.data.map(e => e.banner)
let banner = await api<Site>("banner", {})
return banner.data.map(e=> e.banner)
}

View File

@@ -1,7 +1,7 @@
export default function inView(node, params = { threshold: 0 }) {
let observer
export default function inView(node: Element, params = { threshold: 0 }) {
let observer: IntersectionObserver
const handleIntersect = (e) => {
const handleIntersect = (e: any) => {
const v = e[0].isIntersecting ? "enter" : "exit"
node.dispatchEvent(new CustomEvent(v))
}
@@ -16,7 +16,7 @@ export default function inView(node, params = { threshold: 0 }) {
setObserver(params)
return {
update(params) {
update(params: any) {
setObserver(params)
},

View File

@@ -1,6 +1,6 @@
import { api } from "../../api"
export async function sendForm(body) {
export async function sendForm(body: any) {
let response: any
response = await api("forms", { method: "POST" }, { formular: body })
return response

View File

@@ -1,6 +1,6 @@
export function validateFields(fieldsArray): string[] {
export function validateFields(fieldsArray: (string | boolean | any[])[][]): (string | (() => void))[][] {
const errors = []
let selectedGroup
let selectedGroup: number
const numberRegex = /^[+]?([.]\d+|\d+([.]\d+)?)$/
const emailRegex =
/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/
@@ -15,13 +15,14 @@ export function validateFields(fieldsArray): string[] {
blockContainer[0].classList.add("invalidBlocks")
}
const validateNumber = (value, field, element) => {
const validateNumber = (value: string, field: any, element: HTMLElement) => {
if (!numberRegex.test(`${value}`)) errors.push(["block", () => element.classList.add("border-red")])
}
fieldsArray.forEach(([field, value]) => {
if (field === "blockGroups" || field.includes("numberLabel")) {
if (field === "blockGroups" || (typeof field === "string" && field.includes("numberLabel"))) {
if (!field.includes("numberLabel")) return
// @ts-ignore
const [elementValue, element, group, boolean] = value
if (!elementValue) return
if (selectedGroup !== undefined) {
@@ -33,29 +34,31 @@ export function validateFields(fieldsArray): string[] {
}
return
}
value = value as any[]
let required = value[1]
value = value[0]
if (!required && !value) return
if (!value) {
errors.push(["Eingabe ist erforderlich.", field])
} else if (field.includes("number_")) {
if (!numberRegex.test(`${value}`)) errors.push(["Ungültiger numerischer Wert.", field])
} else if (field.includes("agreement_")) {
if (value !== true) errors.push(["Bitte das Kontrollkästchen anklicken.", field])
} else if (field.includes("Email_")) {
if (!emailRegex.test(value)) errors.push(["Ungültiges E-Mail-Format.", field])
} else if (field.includes("date_")) {
if (!dateRegex.test(value)) errors.push(["Ungültiges Datumsformat.", field])
} else if (field.includes("times_")) {
if (!timeRegex.test(value)) errors.push(["Ungültiges Zeitformat.", field])
} else if (field.includes("Telefon_")) {
if (!phoneRegex.test(value)) errors.push(["Ungültiges Telefonnummernformat.", field])
} else if (typeof field === "string") {
if (field.includes("number_")) {
if (!numberRegex.test(`${value}`)) errors.push(["Ungültiger numerischer Wert.", field])
} else if (field.includes("agreement_")) {
if (value !== true) errors.push(["Bitte das Kontrollkästchen anklicken.", field])
} else if (field.includes("Email_")) {
if (!emailRegex.test(value as string)) errors.push(["Ungültiges E-Mail-Format.", field])
} else if (field.includes("date_")) {
if (!dateRegex.test(value as string)) errors.push(["Ungültiges Datumsformat.", field])
} else if (field.includes("times_")) {
if (!timeRegex.test(value as string)) errors.push(["Ungültiges Zeitformat.", field])
} else if (field.includes("Telefon_")) {
if (!phoneRegex.test(value as string)) errors.push(["Ungültiges Telefonnummernformat.", field])
}
}
})
const blockContainer = document.getElementsByClassName("blockContainer")
// @ts-ignore
if (blockContainer.length && selectedGroup === undefined) {
console.log("NO SELECTED GROUP")
errors.push(["block", wholeBlockInvalid])
}

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import Homepage from "../lib/components/pagebuilder/Homepage.svelte"
import Pagebuilder from "../lib/components/pagebuilder/pagebuilder.svelte"
import Teaser from "../lib/components/pagebuilder/teaser.svelte"
import VideoSwitch from "../lib/components/videoSwitch.svelte"
import { navigation, sites } from "../lib/stores"
let site
function getHomePage(): Site {
let site
let site: Site | undefined
function getHomePage(): Site | undefined {
let site: Site | undefined = undefined
Object.values($sites).forEach((element) => {
if (element.path == "/") site = element
})
@@ -18,12 +18,11 @@
</script>
<main>
{#if site != undefined}
<Homepage />
{#each site.row as row, i}
<Pagebuilder rowNr="{i}" row="{row}" rows="{site?.row}" siteId="{site?.id}" />
{/each}
{#each Object.values($sites) as site, i}
{#if site.showTeaser}
<Teaser site="{site}" index="{i}" />

View File

@@ -2,6 +2,11 @@
import { navigate } from "svelte-routing"
</script>
<svelte:head>
<meta name="robots" content="noindex" />
<meta http-equiv="refresh" content="5; URL=/" />
</svelte:head>
<div class="not-found">
<div class="content">
<h1>404</h1>
@@ -33,17 +38,17 @@
text-align: center;
max-width: @body-small-maxwidth;
padding: 2rem;
background-color: rgba(255, 255, 255, 0.9);
background-color: var(--background-color-90);
h1 {
font-size: 6rem;
color: @banner-color;
color: var(--banner-color);
margin-bottom: 2rem;
}
h2 {
font-size: 2rem;
color: @heading-font-color;
color: var(--heading-font-color);
margin-bottom: 1rem;
}
@@ -58,8 +63,8 @@
transition: background-color 0.2s, color 0.2s;
&:hover {
background-color: @hover-color;
color: @normal-font-color;
background-color: var(--hover-color);
color: var(--normal-font-color);
}
}
}

View File

@@ -3,11 +3,11 @@
import { navigation, sites } from "../lib/stores"
import NotFound from "./NotFound.svelte"
export let path: string
let site = false
function getSelectedSite(path: string): Site {
let site
let site: Site
function getSelectedSite(path: string): Site | {} {
let site = {}
console.log($sites, "sites")
if (Object.values($sites).length == 0) return false
if (Object.values($sites).length == 0) return {}
Object.values($sites).forEach((element) => {
if (element.path == "/" + path) site = element
})
@@ -15,13 +15,45 @@
}
$: {
void $sites
//@ts-ignore
site = getSelectedSite(path)
}
</script>
<svelte:head>
{#key site}
<!-- Title -->
{#if site?.title}
<title>{site.title}</title>
{:else if site?.meta?.titel}
<title>{site.meta.titel}</title>
{:else}
<title>AllKids Erfurt</title>
{/if}
<!-- Description -->
{#if site?.meta?.beschreibung}
<meta name="description" content="{site.meta.beschreibung}" />
{/if}
<!-- Keywords -->
{#if site?.meta?.keywords}
<meta name="keywords" content="{site.meta.keywords}" />
{:else}
<meta
name="keywords"
content="AllKids Erfurt, Second-Hand Kinderkleidung Erfurt, Gebrauchte Kinderspielzeuge Erfurt, AllKids Second-Hand, Erfurt Kinder Second-Hand-Shop, Kinderkleidung Erfurt, Nachhaltige Kinderprodukte Erfurt, AllKids Kinderladen, Second-Hand Babyausstattung Erfurt, AllKids Kleidung Tausch, Erfurt Second-Hand Kinderbücher, AllKids ökologisch, Kinder Second-Hand Markt Erfurt, Günstige Kinderkleidung Erfurt, AllKids Bewertungen, Kinderartikel Kauf und Verkauf Erfurt, Second-Hand Kinderwagen Erfurt, AllKids nachhaltiger Laden, Gebrauchte Kindermöbel Erfurt, AllKids Erfurt Standort"
/>
{/if}
{#if site?.aktiv === false}
<meta name="robots" content="noindex" />
{/if}
{/key}
</svelte:head>
<main class="">
{#if site}
{#each site.row as row, i}
{#if site != undefined}
{#each site.row || [] as row, i}
<Pagebuilder rowNr="{i}" row="{row}" rows="{site?.row}" siteId="{site?.id}" />
{/each}
{:else if site === undefined}