parent
7813f0b486
commit
eee191955e
.yarn/cache
fluent-svelte-npm-1.6.0-b51efa5efd-1b2ac33343.zipfocus-trap-npm-6.9.4-64b032bc16-0b4cebcc11.ziptabbable-npm-5.3.3-baf35cffe9-1aa56e1bb6.zip
api
frontend
media
spa.htmlsrc
types
yarn.lock
BIN
.yarn/cache/fluent-svelte-npm-1.6.0-b51efa5efd-1b2ac33343.zip
vendored
Normal file
BIN
.yarn/cache/fluent-svelte-npm-1.6.0-b51efa5efd-1b2ac33343.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/focus-trap-npm-6.9.4-64b032bc16-0b4cebcc11.zip
vendored
Normal file
BIN
.yarn/cache/focus-trap-npm-6.9.4-64b032bc16-0b4cebcc11.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/tabbable-npm-5.3.3-baf35cffe9-1aa56e1bb6.zip
vendored
Normal file
BIN
.yarn/cache/tabbable-npm-5.3.3-baf35cffe9-1aa56e1bb6.zip
vendored
Normal file
Binary file not shown.
@ -361,6 +361,12 @@ subFields:
|
||||
type: string
|
||||
meta:
|
||||
label: Zeilenname
|
||||
|
||||
- name: showRowName
|
||||
type: boolean
|
||||
meta:
|
||||
label: Zeilenname anzeigen
|
||||
|
||||
- name: columns
|
||||
type: object[]
|
||||
|
||||
@ -598,6 +604,97 @@ subFields:
|
||||
dependsOn:
|
||||
eval: $parent?.showNumber
|
||||
|
||||
- name: showCheckboxGroup
|
||||
type: boolean
|
||||
meta:
|
||||
label: Checkbox Gruppe Anzeigen
|
||||
|
||||
- name: groupTitle
|
||||
type: string
|
||||
meta:
|
||||
label: Checkbox Gruppe Titel
|
||||
dependsOn:
|
||||
eval: $parent.showCheckboxGroup
|
||||
|
||||
- name: checkboxes
|
||||
type: object[]
|
||||
meta:
|
||||
label: Checkbox Gruppe
|
||||
dependsOn:
|
||||
eval: $parent.showCheckboxGroup
|
||||
direction: row
|
||||
subFields:
|
||||
- name: name
|
||||
type: string
|
||||
meta:
|
||||
label: Name
|
||||
|
||||
- name: emailName
|
||||
type: string
|
||||
meta:
|
||||
label: Email Name
|
||||
|
||||
- name: showDatePicker
|
||||
type: boolean
|
||||
meta:
|
||||
label: Datumauswahl anzeigen
|
||||
- name: datePickerEmailTitle
|
||||
type: string
|
||||
meta:
|
||||
label: Datumauswahl Email Titel
|
||||
dependsOn:
|
||||
eval: $parent.showDatePicker
|
||||
|
||||
- name: datePickerNotRequired
|
||||
type: boolean
|
||||
meta:
|
||||
label: nicht Notwendig
|
||||
dependsOn:
|
||||
eval: $parent.showDatePicker
|
||||
|
||||
- name: datePickerProps
|
||||
type: object
|
||||
meta:
|
||||
label: Datumauswahl Eigenschaften
|
||||
dependsOn:
|
||||
eval: $parent.showDatePicker
|
||||
subFields:
|
||||
- name: allowedDateRanges
|
||||
type: object[]
|
||||
meta:
|
||||
label: Erlaubte Datumsbereiche
|
||||
subFields:
|
||||
- name: from
|
||||
type: date
|
||||
meta:
|
||||
label: Von
|
||||
widget: date
|
||||
- name: to
|
||||
type: date
|
||||
meta:
|
||||
label: Bis
|
||||
widget: date
|
||||
- name: excludeDays
|
||||
type: string[]
|
||||
meta:
|
||||
label: Auszuschließende Wochentage
|
||||
widget: selectArray
|
||||
choices:
|
||||
- id: monday
|
||||
name: Montag
|
||||
- id: tuesday
|
||||
name: Dienstag
|
||||
- id: wednesday
|
||||
name: Mittwoch
|
||||
- id: thursday
|
||||
name: Donnerstag
|
||||
- id: friday
|
||||
name: Freitag
|
||||
- id: saturday
|
||||
name: Samstag
|
||||
- id: sunday
|
||||
name: Sonntag
|
||||
|
||||
- name: text
|
||||
type: object[]
|
||||
meta:
|
||||
@ -614,6 +711,12 @@ subFields:
|
||||
meta:
|
||||
label: Platzhalter für das leere Eingabefeld
|
||||
|
||||
- name: textTitle
|
||||
type: string
|
||||
meta:
|
||||
label: Text Titel
|
||||
helperText: Alternative zu textPlaceholder
|
||||
|
||||
- name: textArea
|
||||
type: boolean
|
||||
meta:
|
||||
|
@ -1,13 +1,14 @@
|
||||
const { validateFields } = require("./validateFields")
|
||||
;(function () {
|
||||
if (context.data.formular.honey) {
|
||||
if (context?.data?.formular?.honey) {
|
||||
throw { status: 400, error: "Bot detection" }
|
||||
}
|
||||
delete context.data.formular.honey
|
||||
let values = Object.entries(context.data.formular)
|
||||
|
||||
/**
|
||||
* @type {Array<[string, FormObj]>}
|
||||
*/
|
||||
let values = Object.entries(context?.data?.formular)
|
||||
let validation = validateFields(values)
|
||||
console.log(validation)
|
||||
if (validation.length) {
|
||||
throw { status: 400, error: validation }
|
||||
}
|
||||
|
@ -1,35 +1,54 @@
|
||||
var utils = require("../lib/utils")
|
||||
var config = require("../config")
|
||||
|
||||
;(function () {
|
||||
let formular = context.data.formular
|
||||
/** @type {FormObj} */
|
||||
let formular = context?.data?.formular
|
||||
|
||||
/** @type {TempFormBefore | TempFormAfter} */
|
||||
let tempForm = {}
|
||||
|
||||
let formTitle = `${formular.formTitle}`
|
||||
delete formular.formTitle
|
||||
delete formular["agreement"]
|
||||
delete formular["honey"]
|
||||
formular.formRows.forEach((rowName, i) => {
|
||||
tempForm[rowName] = {}
|
||||
})
|
||||
|
||||
formular?.formRows?.forEach(
|
||||
/** @param {string} rowName */
|
||||
(rowName) => {
|
||||
tempForm[rowName] = {}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {[string, any]} e
|
||||
* @returns {any}
|
||||
*/
|
||||
let getValue = (e) => {
|
||||
if (e[0].includes("numberLabel")) return e[1][0]
|
||||
return e[1]
|
||||
}
|
||||
|
||||
/** @type {TempFormIndices} */
|
||||
let indices = {}
|
||||
|
||||
Object.entries(formular).forEach((e) => {
|
||||
if (e[0] == "formRows") return
|
||||
if (e[0] === "formRows") return
|
||||
|
||||
let key = e[0].split("_")
|
||||
let newKey = key[key.length - 1]
|
||||
let rowName = formular.formRows[Number(key[key.length - 2])]
|
||||
|
||||
// @ts-ignore
|
||||
let rowName = formular?.formRows[Number(key[key.length - 2])]
|
||||
let index = isNaN(Number(key[key.length - 3])) ? 100 : Number(key[key.length - 3])
|
||||
|
||||
if (!rowName) return
|
||||
if (!tempForm[rowName]) tempForm[rowName] = {}
|
||||
|
||||
// @ts-ignore
|
||||
if (tempForm[rowName][newKey]) {
|
||||
// @ts-ignore
|
||||
tempForm[rowName][newKey][0] += "\\" + getValue(e)
|
||||
} else {
|
||||
tempForm[rowName][newKey] = [getValue(e), newKey[0] == "n", newKey.includes("invalid")]
|
||||
// @ts-ignore
|
||||
tempForm[rowName][newKey] = [getValue(e), newKey[0] === "n", newKey.includes("invalid")]
|
||||
indices[rowName] = { ...indices[rowName], [newKey]: index }
|
||||
}
|
||||
})
|
||||
@ -40,12 +59,12 @@ var config = require("../config")
|
||||
.sort((a, b) => indices[rowName][a[0]] - indices[rowName][b[0]])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [key]: val }), {})
|
||||
})
|
||||
console.log(JSON.stringify(tempForm), JSON.stringify(indices))
|
||||
|
||||
Object.keys(tempForm).forEach((row) => {
|
||||
tempForm[row] = Object.entries(tempForm[row])
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
delete tempForm[undefined]
|
||||
context.smtp.sendMail({
|
||||
to: "binkrassdufass@gmail.com",
|
||||
|
@ -1,5 +1,11 @@
|
||||
/**
|
||||
* @param {Array<[string, FormObj]>} fieldsArray
|
||||
* @returns {(string | (() => void))[][]}
|
||||
*/
|
||||
function validateFields(fieldsArray) {
|
||||
/**@type {(string | (() => void))[][]} */
|
||||
const errors = []
|
||||
/**@type {number} */
|
||||
let selectedGroup
|
||||
|
||||
const numberRegex = /^[+]?([.]\d+|\d+([.]\d+)?)$/
|
||||
@ -14,6 +20,12 @@ function validateFields(fieldsArray) {
|
||||
blockContainer.classList.add("invalidBlocks")
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {any} field
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
const validateNumber = (value, field, element) => {
|
||||
if (!numberRegex.test(`${value}`)) {
|
||||
errors.push(["block", () => element.classList.add("border-red")])
|
||||
@ -23,6 +35,7 @@ function validateFields(fieldsArray) {
|
||||
fieldsArray.forEach(([field, value]) => {
|
||||
if (field === "blockGroups" || field.includes("numberLabel")) {
|
||||
if (!field.includes("numberLabel")) return
|
||||
// @ts-ignore
|
||||
const [elementValue, element, group] = value
|
||||
|
||||
if (!elementValue) return
|
||||
|
24
frontend/media/dark.svg
Normal file
24
frontend/media/dark.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="800px" height="800px" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st0{fill:#000000;}
|
||||
]]>
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M403.469,395.031c-129.203,0-233.938-104.75-233.938-233.953c0-62.438,24.5-119.125,64.375-161.078
|
||||
C109.313,17.953,13.563,125.094,13.563,254.656C13.563,396.781,128.781,512,270.906,512c98.688,0,184.359-55.578,227.531-137.125
|
||||
C469.406,387.781,437.297,395.031,403.469,395.031z"/>
|
||||
<path class="st0" d="M349.641,179.328c1.047,1.016,1.516,2.484,1.266,3.922l-8.563,49.938c-0.281,1.672,0.406,3.344,1.766,4.344
|
||||
c1.359,0.984,3.156,1.109,4.656,0.328l44.859-23.578c1.281-0.688,2.813-0.688,4.109,0l44.859,23.578
|
||||
c1.484,0.781,3.297,0.656,4.656-0.328c1.359-1,2.031-2.672,1.75-4.344l-8.563-49.938c-0.25-1.438,0.219-2.906,1.266-3.922
|
||||
L478,143.969c1.203-1.172,1.641-2.938,1.125-4.531c-0.531-1.594-1.906-2.781-3.578-3.016l-50.141-7.297
|
||||
c-1.438-0.203-2.688-1.109-3.344-2.406l-22.422-45.453c-0.734-1.516-2.281-2.453-3.969-2.453c-1.672,0-3.219,0.938-3.953,2.453
|
||||
l-22.438,45.453c-0.641,1.297-1.891,2.203-3.328,2.406l-50.141,7.297c-1.672,0.234-3.063,1.422-3.578,3.016
|
||||
s-0.078,3.359,1.125,4.531L349.641,179.328z"/>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1.5 KiB |
2
frontend/media/light.svg
Normal file
2
frontend/media/light.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#ffffff"><circle cx="32" cy="32" r="16"/><line x1="32" y1="8" x2="32" y2="16"/><line x1="32" y1="56" x2="32" y2="48"/><line x1="56" y1="32" x2="48" y2="32"/><line x1="8" y1="32" x2="16" y2="32"/><line x1="48.97" y1="15.03" x2="43.31" y2="20.69"/><line x1="15.03" y1="48.97" x2="20.69" y2="43.31"/><line x1="48.97" y1="48.97" x2="43.31" y2="43.31"/><line x1="15.03" y1="15.03" x2="20.69" y2="20.69"/></svg>
|
After (image error) Size: 634 B |
@ -1,7 +1,6 @@
|
||||
<?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">
|
||||
<g transform="matrix(4.985044002532959, 0, 0, 5, 1419.3128662109375, 549.1923828125)" id="495873" style="">
|
||||
<filter id="SVGID_40" y="-20%" height="140%" x="-20%" width="140%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="0"/>
|
||||
<feOffset dx="0" dy="0" result="oBlur"/>
|
||||
@ -12,6 +11,10 @@
|
||||
<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)"/>
|
||||
<path style="stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill-rule: nonzero; opacity: 1; filter: url('#SVGID_40'); stroke-width: 0px; stroke: rgb(131, 89, 89); paint-order: stroke; fill: rgb(255, 0, 0);" vector-effect="non-scaling-stroke" d="M -171.628 -28.919 L -149.65 15.437 L -169.43 15.437 L -183.816 -13.934 L -206.593 16.236 L -206.593 90.162 L -224.575 90.162 L -224.575 0.252 L -206.593 -30.318 L -206.593 -5.143 C -206.593 -4.057 -136.463 -109.109 -136.463 -109.838 L -115.684 -109.838 L -152.647 -55.293 L -171.628 -28.919" stroke-linecap="round"/>
|
||||
<path style="stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill-rule: nonzero; opacity: 1; filter: url('#SVGID_40'); stroke-width: 0px; stroke: rgb(131, 89, 89); paint-order: stroke; fill: rgb(255, 0, 0);" vector-effect="non-scaling-stroke" d="M -113.486 90.162 L -134.065 90.162 L -160.839 33.019 L -140.859 33.019 L -113.486 90.162 Z" stroke-linecap="round"/>
|
||||
<path style="stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill-rule: nonzero; opacity: 1; filter: url('#SVGID_40'); stroke-width: 0px; stroke: rgb(131, 89, 89); paint-order: stroke; fill: rgb(255, 255, 0);" vector-effect="non-scaling-stroke" d="M -84.115 64.787 L -103.696 64.787 L -123.476 31.221 L -204.595 31.221 L -204.595 17.235 L -131.868 17.235 L -163.636 -36.711 L -152.847 -51.896 L -84.115 64.787 Z" stroke-linecap="round"/>
|
||||
<path style="stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill-rule: nonzero; opacity: 1; filter: url('#SVGID_40'); stroke-width: 0px; stroke: rgb(131, 89, 89); paint-order: stroke; fill: rgb(255, 255, 0);" vector-effect="non-scaling-stroke" d="M -164.035 -71.277 L -174.625 -55.492 L -184.215 -71.676 L -236.763 17.235 L -226.373 17.235 L -226.373 31.221 L -245.154 31.221 L -264.934 64.787 L -284.715 64.787 L -197.002 -84.064 L -184.683 -105.283 L -171.828 -84.064 L -164.035 -71.277 Z" stroke-linecap="round"/>
|
||||
<path style="stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill-rule: nonzero; opacity: 1; filter: url('#SVGID_40'); stroke-width: 0px; stroke: rgb(131, 89, 89); paint-order: stroke; fill: rgb(255, 0, 0);" vector-effect="non-scaling-stroke" d="M -206.593 -109.838 L -206.593 -71.676 L -224.575 -40.907 L -224.575 -109.838 L -206.593 -109.838 Z" stroke-linecap="round"/>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 1.8 KiB After (image error) Size: 3.2 KiB |
@ -17,7 +17,7 @@
|
||||
<!--HEAD-->
|
||||
<!--PRELOAD-->
|
||||
</head>
|
||||
<body>
|
||||
<body class="">
|
||||
<div id="appContainer"><!--HTML--></div>
|
||||
<script type="module" src="/dist/index.mjs?t=__TIMESTAMP__"></script>
|
||||
<script nomodule src="/dist/index.es5.js?t=__TIMESTAMP__"></script>
|
||||
|
@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { location, navigation, sites, temperature, banner, serviceNavigation } from "./lib/stores"
|
||||
import { location, navigation, sites, banner, serviceNavigation } from "./lib/stores"
|
||||
import Header from "./lib/components/header/Header.svelte"
|
||||
import "fluent-svelte/theme.css"
|
||||
|
||||
import Footer from "./lib/components/Footer.svelte"
|
||||
import { Route, Router } from "svelte-routing"
|
||||
import HomePage from "./routes/HomePage.svelte"
|
||||
@ -44,7 +46,6 @@
|
||||
sitesRes[e.id] = e
|
||||
})
|
||||
$sites = sitesRes
|
||||
console.log("ALARM OVER", $sites)
|
||||
}
|
||||
|
||||
getNavigation()
|
||||
|
@ -10,7 +10,7 @@
|
||||
right: 0;
|
||||
width: 0;
|
||||
bottom: -2px;
|
||||
background: var(--background-color);
|
||||
background: var(--heading-font-color);
|
||||
height: 4px;
|
||||
transition: width 0.5s ease-in;
|
||||
}
|
||||
@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
.fill:hover {
|
||||
color: var(--background-color) !important;
|
||||
color: var(--heading-font-color) !important;
|
||||
div {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
@ -43,7 +43,7 @@
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
width: 0px;
|
||||
background: var(--opposite-bg-color);
|
||||
background: var(--heading-font-color);
|
||||
transition: width 0.5s ease-in;
|
||||
}
|
||||
.fill:hover:after,
|
||||
@ -78,7 +78,7 @@ swiper-slide {
|
||||
z-index: 10000;
|
||||
left: 0px;
|
||||
bottom: -10px;
|
||||
background: var(--opposite-bg-color);
|
||||
background: var(--heading-font-color);
|
||||
height: 5px;
|
||||
width: 0;
|
||||
animation: underlineEffect 4s linear forwards;
|
||||
@ -95,7 +95,7 @@ swiper-slide {
|
||||
|
||||
.swiper-button-prev,
|
||||
.swiper-button-next {
|
||||
color: var(--normal-font-color) !important;
|
||||
color: var(--heading-font-color) !important;
|
||||
height: 70px !important;
|
||||
width: 70px !important;
|
||||
bottom: 0px !important;
|
||||
@ -136,7 +136,7 @@ swiper-slide {
|
||||
@media @desktop {
|
||||
.swiper-button-prev,
|
||||
.swiper-button-next {
|
||||
top: 125px !important;
|
||||
top: 155px !important;
|
||||
transform: scale(1) !important;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,35 @@
|
||||
:root {
|
||||
--background-color: white;
|
||||
--background-color: rgb(235, 221, 221);
|
||||
--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;
|
||||
--normal-font-color-80: rgba(51, 51, 51, 0.8);
|
||||
--normal-font-color-50: rgba(51, 51, 51, 0.5);
|
||||
--normal-font-color-30: rgba(51, 51, 51, 0.3);
|
||||
|
||||
--hover-color: rgb(197, 173, 173);
|
||||
--heading-font-color: #ff0000;
|
||||
--top-heading-font-color: rgb(255, 165, 0);
|
||||
--link-font-color: rgb(255, 165, 0);
|
||||
--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);
|
||||
--opposite-bg-color-80: rgba(24, 24, 24, 0.8);
|
||||
--opposite-bg-color-5: rgba(24, 24, 24, 0.05);
|
||||
}
|
||||
|
||||
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-80: rgba(209, 209, 209, 0.8);
|
||||
--normal-font-color-50: rgba(209, 209, 209, 0.5);
|
||||
--normal-font-color-30: rgba(209, 209, 209, 0.3);
|
||||
--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;
|
||||
--top-heading-font-color: rgb(200, 106, 0);
|
||||
--link-font-color: rgb(200, 106, 0);
|
||||
--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);
|
||||
@ -75,9 +85,8 @@ ol {
|
||||
|
||||
/* Links */
|
||||
a {
|
||||
color: var(--link-font-color);
|
||||
text-decoration: underline;
|
||||
font-weight: 700;
|
||||
color: var(--normal-font-color);
|
||||
}
|
||||
|
||||
/* Tabellen */
|
||||
@ -92,16 +101,6 @@ table {
|
||||
right 0.5s ease, transform 0.5s ease;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: var(--background-color-90);
|
||||
}
|
||||
button {
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { navigate } from "svelte-routing"
|
||||
import { serviceNavigation, sites } from "../stores"
|
||||
import { serviceNavigation, sites, darkMode } from "../stores"
|
||||
</script>
|
||||
|
||||
<div class="footer">
|
||||
@ -37,12 +37,20 @@
|
||||
{/each}
|
||||
</div>
|
||||
<button
|
||||
class="darklight"
|
||||
on:click="{() => {
|
||||
const body = document.querySelector('body')
|
||||
if (body) body.classList.toggle('darkTheme')
|
||||
if (body) {
|
||||
body.classList.toggle('darkTheme')
|
||||
}
|
||||
$darkMode = !$darkMode
|
||||
}}"
|
||||
>
|
||||
toggletheme
|
||||
{#if !$darkMode}
|
||||
<img src="/media/dark.svg" alt="darkmode" />
|
||||
{:else}
|
||||
<img src="/media/light.svg" alt="lightmode" />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -51,6 +59,15 @@
|
||||
.social {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.darklight {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
object-fit: contain;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
margin-top: 60px;
|
||||
width: 100vw;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { navigation, sites } from "../../stores"
|
||||
import { darkMode, navigation, sites } from "../../stores"
|
||||
|
||||
import { apiBaseURL } from "../../../config"
|
||||
import { navigate } from "svelte-routing"
|
||||
@ -60,9 +60,11 @@
|
||||
navigate('/')
|
||||
}}"
|
||||
>
|
||||
<button class="img-logo-container"><img src="/media/logo.svg" alt="logo" /></button>
|
||||
<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="upper"><span class="yellow">ALL</span> <span class="red">KIDS</span></p>
|
||||
<p id="lower">SO GÜNSTIG WIE NACHHALTIG</p>
|
||||
</div>
|
||||
</button>
|
||||
@ -202,12 +204,22 @@
|
||||
text-align: left;
|
||||
}
|
||||
& > #upper {
|
||||
font-family: "Orbitron" !important;
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
span {
|
||||
font-family: "Orbitron" !important;
|
||||
font-size: 31px;
|
||||
font-weight: 700;
|
||||
&.red {
|
||||
color: red;
|
||||
}
|
||||
&.yellow {
|
||||
color: yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
& > #lower {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: orange;
|
||||
}
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
@ -258,7 +270,7 @@
|
||||
overflow: hidden;
|
||||
width: 100vw;
|
||||
z-index: 2000;
|
||||
background-color: var(--opposite-bg-color-80);
|
||||
background-color: rgba(0, 0, 0, 0.849);
|
||||
opacity: 0;
|
||||
.inner-container {
|
||||
width: 100%;
|
||||
|
@ -27,7 +27,6 @@
|
||||
}
|
||||
|
||||
function imageSlide(images: HTMLImageElement[]) {
|
||||
console.log(images)
|
||||
let currentImage = 0
|
||||
images[0].classList.add("show-img")
|
||||
let interval = setInterval(() => {
|
||||
@ -59,9 +58,11 @@
|
||||
navigate('/')
|
||||
}}"
|
||||
>
|
||||
<button class="img-logo-container"><img src="/media/logo.svg" alt="logo" /></button>
|
||||
<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="upper"><span class="yellow">ALL</span> <span class="red">KIDS</span></p>
|
||||
<p id="lower">SO GÜNSTIG WIE NACHHALTIG</p>
|
||||
</div>
|
||||
</button>
|
||||
@ -241,12 +242,22 @@
|
||||
text-align: left;
|
||||
}
|
||||
& > #upper {
|
||||
font-family: "Orbitron" !important;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
span {
|
||||
font-family: "Orbitron" !important;
|
||||
font-size: 31px;
|
||||
font-weight: 700;
|
||||
&.red {
|
||||
color: red;
|
||||
}
|
||||
&.yellow {
|
||||
color: yellow;
|
||||
}
|
||||
}
|
||||
}
|
||||
& > #lower {
|
||||
font-size: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: orange;
|
||||
}
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
|
@ -23,7 +23,6 @@
|
||||
}
|
||||
|
||||
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
|
||||
@ -159,6 +158,7 @@
|
||||
line-height: 1;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
color: var(--heading-font-color);
|
||||
}
|
||||
|
||||
h2 {
|
||||
@ -168,6 +168,7 @@
|
||||
}
|
||||
line-height: 1;
|
||||
font-weight: 500;
|
||||
color: var(--top-heading-font-color);
|
||||
}
|
||||
}
|
||||
.description {
|
||||
|
399
frontend/src/lib/components/pagebuilder/form/Formular.svelte
Normal file
399
frontend/src/lib/components/pagebuilder/form/Formular.svelte
Normal file
@ -0,0 +1,399 @@
|
||||
<script lang="ts">
|
||||
import Form from "./form.svelte"
|
||||
import MobileForm from "./mobileForm.svelte"
|
||||
import { writable } from "svelte/store"
|
||||
import { validateFields } from "../../../functions/validateFields"
|
||||
import { sendForm } from "../../../functions/sendForm"
|
||||
import { navigate } from "svelte-routing"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
export let col: Column
|
||||
export let siteId: string
|
||||
export let rowNr: number
|
||||
export let row: Row
|
||||
export let rows: Row[]
|
||||
|
||||
let formSend = false
|
||||
let formValues = writable<FormValues>({})
|
||||
|
||||
function submitForm() {
|
||||
const values: Array<ValueEntry> = Object.entries($formValues).map((entry: ObjectEntry) => {
|
||||
const key: string = entry[0]
|
||||
const value: CustomHTMLElement = entry[1]
|
||||
if (!key.includes("numberLabel")) {
|
||||
return [key, [value.checked || value.value, value.required]] as ValueEntry
|
||||
} else {
|
||||
return [key, [value.value, value, value.getAttribute("name"), value.required]] as ValueEntry
|
||||
}
|
||||
})
|
||||
|
||||
const fields: Array<ValueEntry> = values.filter((entry: ValueEntry) => !entry[0].includes("label"))
|
||||
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] as string
|
||||
label?.appendChild(errorElement)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// @ts-ignore
|
||||
const formObj: FormObj = {}
|
||||
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]
|
||||
}
|
||||
})
|
||||
let form: any
|
||||
row.column.forEach((col) => {
|
||||
if (col.contentType == "form") form = col
|
||||
})
|
||||
if (!form) return
|
||||
formObj["formRows"] = form.formRows.map((r: FormRow) => r.rowName)
|
||||
formObj["formTitle"] = form.formEmailTitle
|
||||
formSend = true
|
||||
const hny = document.getElementById("hny") as HTMLInputElement
|
||||
if (hny) formObj["honey"] = hny.checked
|
||||
sendForm(formObj)
|
||||
}
|
||||
}
|
||||
let innerWidth = window.innerWidth
|
||||
|
||||
onMount(() => {
|
||||
const handleResize = () => {
|
||||
innerWidth = window.innerWidth
|
||||
}
|
||||
|
||||
window.addEventListener("resize", handleResize)
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if formSend}
|
||||
<div class="success-message">
|
||||
<h1>Formular erfolgreich gesendet!</h1>
|
||||
<p>Vielen Dank für Ihre Anfrage. Wir werden uns in Kürze bei Ihnen melden.</p>
|
||||
</div>
|
||||
{:else}
|
||||
<form
|
||||
class="form-rows"
|
||||
on:submit="{(e) => {
|
||||
e.preventDefault()
|
||||
submitForm()
|
||||
}}"
|
||||
>
|
||||
{#each col.formRows ?? [] as formRow, i}
|
||||
{#if innerWidth < 768}
|
||||
<MobileForm formRow="{formRow}" formValues="{formValues}" index="{i}" />
|
||||
{:else}
|
||||
<Form formRow="{formRow}" formValues="{formValues}" index="{i}" />
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="row additional">
|
||||
<div class="data-protection">
|
||||
<label bind:this="{$formValues[`agreement_label`]}">
|
||||
<input
|
||||
required="{true}"
|
||||
class="checkit"
|
||||
type="checkbox"
|
||||
on:change="{(e) => {
|
||||
let element = e.currentTarget
|
||||
element.classList.remove('invalid')
|
||||
}}"
|
||||
bind:this="{$formValues['agreement']}"
|
||||
/>
|
||||
<span class="checkit-span"></span>
|
||||
</label>
|
||||
|
||||
<div class="datasec">
|
||||
<button on:click|preventDefault="{() => navigate('/datenschutz')}" class="link">
|
||||
Datenschutz
|
||||
</button>
|
||||
akzeptieren
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
name="contact_me_by_fax_only"
|
||||
id="hny"
|
||||
value="1"
|
||||
style="display:none !important"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button class="submit-request" type="submit">Anfrage absenden</button>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<style lang="less" global>
|
||||
@import "../../../assets/css/variables.less";
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.data-protection {
|
||||
margin: 5px 0px;
|
||||
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
|
||||
}
|
||||
|
||||
.success-message {
|
||||
h1 {
|
||||
color: var(--heading-font-color);
|
||||
font-size: 36px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
.invalidBlocks {
|
||||
border: 2px solid rgb(255, 0, 0) !important;
|
||||
position: relative;
|
||||
&::after {
|
||||
font-size: 0.9rem !important;
|
||||
color: red !important;
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
content: "Bitte wähle entweder eine Kartenanzahl oder einen Wunschbetrag aus.";
|
||||
}
|
||||
}
|
||||
|
||||
.border-red {
|
||||
border-color: red !important;
|
||||
}
|
||||
|
||||
.no-margin {
|
||||
margin-top: 15px !important;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border: 2px solid red !important;
|
||||
}
|
||||
.error-message {
|
||||
font-size: 0.9rem !important;
|
||||
color: red !important;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
.checkit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkit-span {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border: 1px solid grey;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[type="checkbox"]:checked + span:before {
|
||||
content: "\2714";
|
||||
position: absolute;
|
||||
transform-origin: bottom;
|
||||
}
|
||||
|
||||
.form-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
h3 {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: 1.5rem;
|
||||
|
||||
.date {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
label {
|
||||
width: 100% !important;
|
||||
font-size: inherit;
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
.form-cols {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-column {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
width: 100%;
|
||||
gap: 1rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--hover-color);
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.data-protection {
|
||||
padding: 10px 20px;
|
||||
border: 0px solid var(--opposite-bg-color);
|
||||
border-bottom: 3px solid var(--heading-font-color);
|
||||
outline: 0px solid var(--opposite-bg-color);
|
||||
color: var(--opposite-bg-color);
|
||||
background-color: var(--background-color);
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.data-protection {
|
||||
display: flex;
|
||||
|
||||
flex-wrap: nowrap;
|
||||
gap: 5px !important;
|
||||
justify-content: start;
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
input[type="date"] {
|
||||
font-family: inherit;
|
||||
width: 100% !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 10px 20px;
|
||||
border: 0;
|
||||
border-bottom: 3px solid var(--heading-font-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
select:focus {
|
||||
border-bottom-color: var(--heading-font-color);
|
||||
}
|
||||
|
||||
#time-select {
|
||||
appearance: none;
|
||||
background-image: url("../../../../../media/clock.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 20px center;
|
||||
background-size: 18px;
|
||||
|
||||
option {
|
||||
padding: 10px 20px;
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
}
|
||||
@media @mobile {
|
||||
.date {
|
||||
width: 100vw !important;
|
||||
}
|
||||
}
|
||||
@media @tablet {
|
||||
.date {
|
||||
width: 100% !important;
|
||||
}
|
||||
.form-cols {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
}
|
||||
i .max-width {
|
||||
max-width: @body-maxwidth !important;
|
||||
}
|
||||
|
||||
.datasec {
|
||||
display: flex;
|
||||
align-items: center !important;
|
||||
.link {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-end !important;
|
||||
text-decoration: underline;
|
||||
margin-right: 3px;
|
||||
color: rgb(14, 91, 146);
|
||||
}
|
||||
}
|
||||
|
||||
.additional {
|
||||
display: flex;
|
||||
@media @mobile {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
@media @tablet {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
gap: 2.5rem;
|
||||
div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
.submit-request {
|
||||
flex: 1;
|
||||
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
background-color: var(--heading-font-color);
|
||||
color: var(--background-color);
|
||||
padding: 10px 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
18
frontend/src/lib/components/pagebuilder/form/checkbox.svelte
Normal file
18
frontend/src/lib/components/pagebuilder/form/checkbox.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
export let label = "" // Der Text, der neben der Checkbox angezeigt wird
|
||||
export let bindValue: any // Der Wert der Checkbox
|
||||
export let formValues: Writable<FormValues> // Das formValues-Objekt aus dem übergeordneten Komponenten
|
||||
export let id = "" // Eindeutige ID für die Checkbox, um den Label korrekt zuzuweisen
|
||||
export let name = "" // Name des Formularelements
|
||||
</script>
|
||||
|
||||
<label class="checkbox-container" for="{id}">
|
||||
<input type="checkbox" bind:checked="{bindValue}" id="{id}" name="{name}" bind:this="{formValues[name]}" />
|
||||
<span>{label}</span>
|
||||
</label>
|
||||
|
||||
<style>
|
||||
/* Sie können hier den Stil für Ihre Checkbox anpassen */
|
||||
</style>
|
@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import type { Writable } from "svelte/store"
|
||||
export let groupTitle: string
|
||||
export let checkboxes: { name: string; emailName: string }[]
|
||||
export let formValues: Writable<FormValues>
|
||||
export let rowNr: number
|
||||
</script>
|
||||
|
||||
<div class="checkbox-group">
|
||||
<h3>{groupTitle}</h3>
|
||||
<div class="containerr">
|
||||
{#each checkboxes as checkbox, i}
|
||||
<label class="checkbox-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox-input checkit"
|
||||
bind:this="{$formValues[`checkbox_${groupTitle}_${rowNr}_${checkbox.emailName}`]}"
|
||||
/>
|
||||
<span class="checkit-span"></span>
|
||||
{checkbox.name}
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="less">
|
||||
.checkbox-group {
|
||||
.checkbox-input {
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
width: fit-content !important;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
& > .containerr {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
131
frontend/src/lib/components/pagebuilder/form/datepicker.svelte
Normal file
131
frontend/src/lib/components/pagebuilder/form/datepicker.svelte
Normal file
@ -0,0 +1,131 @@
|
||||
<script lang="ts">
|
||||
import { CalendarView } from "fluent-svelte"
|
||||
|
||||
export let groupTitle: string
|
||||
export let datePickerProps: DatePickerProps
|
||||
export let formValues: any
|
||||
export let rowNr: number
|
||||
export let formCol: FormColumn
|
||||
|
||||
const today = new Date()
|
||||
const oneYearFromNow = new Date(today)
|
||||
oneYearFromNow.setFullYear(today.getFullYear() + 1)
|
||||
const indexToDay: Record<number, string> = {
|
||||
0: "sunday",
|
||||
1: "monday",
|
||||
2: "tuesday",
|
||||
3: "wednesday",
|
||||
4: "thursday",
|
||||
5: "friday",
|
||||
6: "saturday",
|
||||
}
|
||||
|
||||
function generateBlackoutDates(props: DatePickerProps): Date[] {
|
||||
let blackoutDates = []
|
||||
|
||||
// Funktion, um einen ISO-String in ein vereinfachtes Date-Objekt umzuwandeln
|
||||
const dateFromISOString = (isoString: string) => {
|
||||
const date = new Date(isoString)
|
||||
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()))
|
||||
}
|
||||
|
||||
const dayToIndex: Record<string, number> = {
|
||||
sunday: 0,
|
||||
monday: 1,
|
||||
tuesday: 2,
|
||||
wednesday: 3,
|
||||
thursday: 4,
|
||||
friday: 5,
|
||||
saturday: 6,
|
||||
}
|
||||
|
||||
// Initialisiere ein aktuelles Datum auf heute
|
||||
let currentDate = new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate()))
|
||||
|
||||
// Schleife durch die nächsten 365 Tage
|
||||
for (let i = 0; i <= 365; i++) {
|
||||
// Überprüfen, ob dieses Datum erlaubt ist
|
||||
const isAllowed = props.allowedDateRanges.some((range) => {
|
||||
const fromDate = dateFromISOString(range.from)
|
||||
const toDate = dateFromISOString(range.to)
|
||||
|
||||
return currentDate >= fromDate && currentDate <= toDate
|
||||
})
|
||||
|
||||
// Überprüfen, ob der Wochentag ausgeschlossen ist
|
||||
const currentDayIndex = currentDate.getUTCDay()
|
||||
const currentDayString = indexToDay[currentDayIndex]
|
||||
const isExcluded = props.excludeDays?.includes(currentDayString)
|
||||
|
||||
// Wenn nicht erlaubt oder ausgeschlossen, zu den Blackout-Daten hinzufügen
|
||||
if (!isAllowed || isExcluded) {
|
||||
blackoutDates.push(new Date(currentDate))
|
||||
}
|
||||
|
||||
// Zum nächsten Tag wechseln
|
||||
currentDate.setUTCDate(currentDate.getUTCDate() + 1)
|
||||
}
|
||||
|
||||
return blackoutDates
|
||||
}
|
||||
|
||||
let value = new Date()
|
||||
const blackoutDates = generateBlackoutDates(datePickerProps)
|
||||
|
||||
function setFormValues() {
|
||||
$formValues[`datepicker_${groupTitle}_${rowNr}_${formCol.datePickerEmailTitle}`] = {
|
||||
value: value.toLocaleDateString("de-DE"),
|
||||
required: !formCol.datePickerNotRequired,
|
||||
}
|
||||
}
|
||||
//needs email conntection
|
||||
$: {
|
||||
if (value) {
|
||||
setFormValues()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="container">
|
||||
<div
|
||||
class="datepicker"
|
||||
on:click|preventDefault|stopPropagation
|
||||
on:keydown|stopPropagation
|
||||
on:submit|stopPropagation|preventDefault
|
||||
>
|
||||
<CalendarView
|
||||
weekStart="{1}"
|
||||
bind:vaue="{value}"
|
||||
on:change="{(e) => {
|
||||
value = e.detail
|
||||
}}"
|
||||
min="{today}"
|
||||
max="{oneYearFromNow}"
|
||||
blackout="{blackoutDates}"
|
||||
locale="de-DE"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="less">
|
||||
@import url("https://unpkg.com/fluent-svelte/theme.css");
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
--fds-solid-background-quarternary: var(--background-color);
|
||||
--fds-text-primary: var(--normal-font-color);
|
||||
--fds-text-secondary: var(--normal-font-color-80);
|
||||
--fds-text-tertiary: var(--normal-font-color-50);
|
||||
--fds-text-disabled: var(--normal-font-color-30);
|
||||
--fds-accent-disabled: var(--opposite-bg-color-5);
|
||||
--fds-control-strong-stroke-default: var(--opposite-bg-color-80);
|
||||
.datepicker {
|
||||
width: fit-content;
|
||||
margin: 5px 0px;
|
||||
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import CheckboxGroup from "./checkboxGroup.svelte"
|
||||
import Datepicker from "./datepicker.svelte"
|
||||
import FormLabelNumberBlock from "./formLabelNumberBlock.svelte"
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
@ -24,6 +26,9 @@
|
||||
</script>
|
||||
|
||||
<div class="form-row">
|
||||
<h3 style="margin-bottom: -0.5rem;">
|
||||
{#if formRow.showRowName}{formRow.rowName || ""}{/if}
|
||||
</h3>
|
||||
<div class="form-cols">
|
||||
{#each formRow.columns as column, columnIndex}
|
||||
<div class="form-column">
|
||||
@ -48,7 +53,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>
|
||||
@ -114,49 +119,70 @@
|
||||
</label>
|
||||
{/if}
|
||||
|
||||
{#each column.text || [] as textField, textFieldIndex}
|
||||
{#if textField?.textArea}
|
||||
<label bind:this="{$formValues[`textarea_Nachricht_label`]}">
|
||||
<textarea
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
on:change="{removeInvalid}"
|
||||
{#if column.showCheckboxGroup}
|
||||
<CheckboxGroup
|
||||
checkboxes="{column.checkboxes}"
|
||||
groupTitle="{column.groupTitle}"
|
||||
formValues="{formValues}"
|
||||
rowNr="{index}"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if column.showDatePicker}
|
||||
<Datepicker
|
||||
datePickerProps="{column.datePickerProps}"
|
||||
groupTitle="{column.groupTitle}"
|
||||
formValues="{formValues}"
|
||||
rowNr="{index}"
|
||||
formCol="{column}"
|
||||
|
||||
/>
|
||||
{/if}
|
||||
{#each column.text ?? [] as textField, textFieldIndex}
|
||||
<div>
|
||||
<h3 class="textTitle">{textField.textTitle || ""}</h3>
|
||||
{#if textField?.textArea}
|
||||
<label bind:this="{$formValues[`textarea_Nachricht_label`]}">
|
||||
<textarea
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
on:change="{removeInvalid}"
|
||||
bind:this="{$formValues[
|
||||
`textarea_Nachricht_${textField.textfieldOrder}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"></textarea>
|
||||
</label>
|
||||
{:else}
|
||||
<label
|
||||
bind:this="{$formValues[
|
||||
`textarea_Nachricht_${textField.textfieldOrder}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"></textarea>
|
||||
</label>
|
||||
{:else}
|
||||
<label
|
||||
bind:this="{$formValues[
|
||||
`input_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_label`
|
||||
]}"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
on:change="{removeInvalid}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
bind:this="{$formValues[
|
||||
`${
|
||||
textField?.telValidation
|
||||
? 'Telefon'
|
||||
: textField?.emailValidation
|
||||
? 'Email'
|
||||
: 'input'
|
||||
}_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_${
|
||||
textField.textfieldOrder
|
||||
}_${index}_${textField.emailName || columnIndex + 'invalidtext' + textFieldIndex}`
|
||||
`input_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_label`
|
||||
]}"
|
||||
/>
|
||||
</label>
|
||||
{/if}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
on:change="{removeInvalid}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
bind:this="{$formValues[
|
||||
`${
|
||||
textField?.telValidation
|
||||
? 'Telefon'
|
||||
: textField?.emailValidation
|
||||
? 'Email'
|
||||
: 'input'
|
||||
}_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_${
|
||||
textField.textfieldOrder
|
||||
}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"
|
||||
/>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
|
@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import FormLabelNumberBlock from "./formLabelNumberBlock.svelte"
|
||||
import type { Writable } from "svelte/store"
|
||||
|
||||
import CheckboxGroup from "./checkboxGroup.svelte"
|
||||
import Datepicker from "./datepicker.svelte"
|
||||
export let formRow: FormRow
|
||||
export let formValues: Writable<FormValues>
|
||||
export let index: number
|
||||
@ -126,46 +127,69 @@
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if column.showCheckboxGroup}
|
||||
<CheckboxGroup
|
||||
checkboxes="{column.checkboxes}"
|
||||
groupTitle="{column.groupTitle}"
|
||||
formValues="{formValues}"
|
||||
rowNr="{index}"
|
||||
/>
|
||||
{/if}
|
||||
{#if column.showDatePicker}
|
||||
<Datepicker
|
||||
datePickerProps="{column.datePickerProps}"
|
||||
groupTitle="{column.groupTitle}"
|
||||
formValues="{formValues}"
|
||||
rowNr="{index}"
|
||||
formCol="{column}"
|
||||
/>
|
||||
{/if}
|
||||
{#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`]}">
|
||||
<textarea
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
on:change="{removeInvalid}"
|
||||
<h3 class="textTitle">{textField.textTitle || ""}</h3>
|
||||
<div
|
||||
class="column-{columnIndex} position-{getPosition(column, 5 + textFieldIndex, textFieldIndex)}"
|
||||
>
|
||||
{#if textField?.textArea}
|
||||
<label bind:this="{$formValues[`textarea_Nachricht_label`]}">
|
||||
<textarea
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
on:change="{removeInvalid}"
|
||||
bind:this="{$formValues[
|
||||
`textarea_Nachricht_${textField.textfieldOrder}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"></textarea>
|
||||
</label>
|
||||
{:else}
|
||||
<label
|
||||
bind:this="{$formValues[
|
||||
`textarea_Nachricht_${textField.textfieldOrder}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"></textarea>
|
||||
</label>
|
||||
{:else}
|
||||
<label
|
||||
bind:this="{$formValues[
|
||||
`input_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_label`
|
||||
]}"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
on:change="{removeInvalid}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
bind:this="{$formValues[
|
||||
`${
|
||||
textField?.telValidation
|
||||
? 'Telefon'
|
||||
: textField?.emailValidation
|
||||
? 'Email'
|
||||
: 'input'
|
||||
}_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_${
|
||||
textField.textfieldOrder
|
||||
}_${index}_${textField.emailName || columnIndex + 'invalidtext' + textFieldIndex}`
|
||||
`input_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_label`
|
||||
]}"
|
||||
/>
|
||||
</label>
|
||||
{/if}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="{textField?.textPlaceholder}"
|
||||
on:change="{removeInvalid}"
|
||||
required="{textField?.notRequired !== true}"
|
||||
bind:this="{$formValues[
|
||||
`${
|
||||
textField?.telValidation
|
||||
? 'Telefon'
|
||||
: textField?.emailValidation
|
||||
? 'Email'
|
||||
: 'input'
|
||||
}_${column.title ? column.title + '_' : ''}${textField?.textPlaceholder}_${
|
||||
textField.textfieldOrder
|
||||
}_${index}_${
|
||||
textField.emailName || columnIndex + 'invalidtext' + textFieldIndex
|
||||
}`
|
||||
]}"
|
||||
/>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
|
@ -7,81 +7,20 @@
|
||||
import MainPicture from "./mainPicture.svelte"
|
||||
import TextContent from "./textContent.svelte"
|
||||
import Table from "./table.svelte"
|
||||
import Form from "./form/form.svelte"
|
||||
import MobileForm from "./form/mobileForm.svelte"
|
||||
import Formular from "./form/Formular.svelte"
|
||||
import { writable } from "svelte/store"
|
||||
import { validateFields } from "../../functions/validateFields"
|
||||
import { sendForm } from "../../functions/sendForm"
|
||||
import GoogleMaps from "../googleMaps.svelte"
|
||||
import { navigate } from "svelte-routing"
|
||||
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<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") ? "max-width" : "small-max-width"
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
const values = Object.entries($formValues).map((entry) => {
|
||||
return [
|
||||
entry[0],
|
||||
!entry[0].includes("numberLabel")
|
||||
? [entry[1].checked || entry[1].value, entry[1].required]
|
||||
: [entry[1].value, entry[1], entry[1].getAttribute("name"), entry[1].required],
|
||||
]
|
||||
})
|
||||
|
||||
const fields = values.filter((entry) => !entry[0].includes("label"))
|
||||
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] as string
|
||||
label?.appendChild(errorElement)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
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]
|
||||
}
|
||||
})
|
||||
let form: any
|
||||
row.column.forEach((col) => {
|
||||
if (col.contentType == "form") form = col
|
||||
})
|
||||
if (!form) return
|
||||
formObj["formRows"] = form.formRows.map((r: FormRow) => r.rowName)
|
||||
formObj["formTitle"] = form.formEmailTitle
|
||||
formSend = true
|
||||
const hny = document.getElementById("hny") as HTMLInputElement
|
||||
if (hny) formObj["honey"] = hny.checked
|
||||
sendForm(formObj)
|
||||
}
|
||||
}
|
||||
let innerWidth = window.innerWidth
|
||||
</script>
|
||||
|
||||
<main class="row" name="{row.title}" class:max-width="{getRowClass(row) === 'max-width'}" id="{`RowNr` + rowNr}">
|
||||
@ -112,63 +51,7 @@
|
||||
<GoogleMaps />
|
||||
{/if}
|
||||
{:else if col.contentType == "form"}
|
||||
{#if formSend}
|
||||
<div class="success-message">
|
||||
<h1>Formular erfolgreich gesendet!</h1>
|
||||
<p>Vielen Dank für Ihre Anfrage. Wir werden uns in Kürze bei Ihnen melden.</p>
|
||||
</div>
|
||||
{:else}
|
||||
<form
|
||||
class="form-rows"
|
||||
on:submit="{(e) => {
|
||||
e.preventDefault()
|
||||
submitForm()
|
||||
}}"
|
||||
>
|
||||
{#each col.formRows ?? [] as formRow, i}
|
||||
{#if innerWidth < 768}
|
||||
<MobileForm formRow="{formRow}" formValues="{formValues}" index="{i}" />
|
||||
{:else}
|
||||
<Form formRow="{formRow}" formValues="{formValues}" index="{i}" />
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="row additional">
|
||||
<div class="data-protection">
|
||||
<label bind:this="{$formValues[`agreement_label`]}">
|
||||
<input
|
||||
required="{true}"
|
||||
class="checkit"
|
||||
type="checkbox"
|
||||
on:change="{(e) => {
|
||||
let element = e.currentTarget
|
||||
element.classList.remove('invalid')
|
||||
}}"
|
||||
bind:this="{$formValues['agreement']}"
|
||||
/>
|
||||
<span class="checkit-span"></span>
|
||||
</label>
|
||||
|
||||
<div class="datasec">
|
||||
<button on:click|preventDefault="{() => navigate('/datenschutz')}" class="link">
|
||||
Datenschutz
|
||||
</button>
|
||||
akzeptieren
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
name="contact_me_by_fax_only"
|
||||
id="hny"
|
||||
value="1"
|
||||
style="display:none !important"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button class="submit-request" type="submit">Anfrage absenden</button>
|
||||
</div>
|
||||
</form>
|
||||
{/if}
|
||||
<Formular col="{col}" siteId="{siteId}" rowNr="{rowNr}" row="{row}" rows="{rows}" />
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
@ -176,45 +59,6 @@
|
||||
|
||||
<style lang="less" global>
|
||||
@import "../../assets/css/variables.less";
|
||||
.wave-placeholder {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.data-protection {
|
||||
margin: 5px 0px;
|
||||
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
|
||||
}
|
||||
|
||||
.success-message {
|
||||
h1 {
|
||||
color: var(--heading-font-color);
|
||||
font-size: 36px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
.invalidBlocks {
|
||||
border: 2px solid rgb(255, 0, 0) !important;
|
||||
position: relative;
|
||||
&::after {
|
||||
font-size: 0.9rem !important;
|
||||
color: red !important;
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
content: "Bitte wähle entweder eine Kartenanzahl oder einen Wunschbetrag aus.";
|
||||
}
|
||||
}
|
||||
|
||||
.border-red {
|
||||
border-color: red !important;
|
||||
}
|
||||
|
||||
.row-title {
|
||||
font-size: 1.6rem;
|
||||
@ -234,15 +78,6 @@
|
||||
margin-top: 15px !important;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-bottom: 2px solid red !important;
|
||||
}
|
||||
.error-message {
|
||||
font-size: 0.9rem !important;
|
||||
color: red !important;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
padding: 0px 0px 15px 0;
|
||||
@ -251,18 +86,6 @@
|
||||
align-items: center;
|
||||
max-width: @body-small-maxwidth;
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none; /* Remove default bullet points */
|
||||
padding: 0;
|
||||
@ -290,175 +113,6 @@
|
||||
& > h3 {
|
||||
width: 100%;
|
||||
}
|
||||
.checkit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkit-span {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border: 1px solid grey;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[type="checkbox"]:checked + span:before {
|
||||
content: "\2714";
|
||||
position: absolute;
|
||||
transform-origin: bottom;
|
||||
}
|
||||
&.additional {
|
||||
display: flex;
|
||||
|
||||
@media @mobile {
|
||||
flex-direction: column;
|
||||
}
|
||||
@media @tablet {
|
||||
flex-direction: row;
|
||||
}
|
||||
gap: 2.5rem;
|
||||
div {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
}
|
||||
.submit-request {
|
||||
flex: 1;
|
||||
box-shadow: 0 0 25px 10px var(--opposite-bg-color-5);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
background-color: var(--heading-font-color);
|
||||
color: var(--background-color);
|
||||
padding: 10px 20px;
|
||||
}
|
||||
}
|
||||
.form-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
h3 {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: 1.5rem;
|
||||
|
||||
.date {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
label {
|
||||
width: 100% !important;
|
||||
font-size: inherit;
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
.form-cols {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-column {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--hover-color);
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
.data-protection {
|
||||
padding: 10px 20px;
|
||||
border: 0px solid var(--opposite-bg-color);
|
||||
border-bottom: 3px solid var(--heading-font-color);
|
||||
outline: 0px solid var(--opposite-bg-color);
|
||||
color: var(--opposite-bg-color);
|
||||
background-color: var(--background-color);
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.data-protection {
|
||||
display: flex;
|
||||
|
||||
flex-wrap: nowrap;
|
||||
gap: 5px !important;
|
||||
justify-content: start;
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
input[type="date"] {
|
||||
font-family: inherit;
|
||||
width: 100% !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 10px 20px;
|
||||
border: 0;
|
||||
border-bottom: 3px solid var(--heading-font-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
select:focus {
|
||||
border-bottom-color: var(--heading-font-color);
|
||||
}
|
||||
|
||||
#time-select {
|
||||
appearance: none;
|
||||
background-image: url("../../../../media/clock.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 20px center;
|
||||
background-size: 18px;
|
||||
|
||||
option {
|
||||
padding: 10px 20px;
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
}
|
||||
@media @mobile {
|
||||
.date {
|
||||
width: 100vw !important;
|
||||
}
|
||||
}
|
||||
@media @tablet {
|
||||
.date {
|
||||
width: 100% !important;
|
||||
}
|
||||
.form-cols {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media @mobile {
|
||||
.no-gap {
|
||||
@ -507,17 +161,4 @@
|
||||
.max-width {
|
||||
max-width: @body-maxwidth !important;
|
||||
}
|
||||
|
||||
.datasec {
|
||||
display: flex;
|
||||
align-items: center !important;
|
||||
.link {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: flex-end !important;
|
||||
text-decoration: underline;
|
||||
margin-right: 3px;
|
||||
color: rgb(14, 91, 146);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
register(false)
|
||||
let swiper: any
|
||||
console.log("TST RENDERED")
|
||||
onMount(async () => {
|
||||
if (swiper) {
|
||||
const response = await fetch("/dist/index.css")
|
||||
|
@ -1,4 +1,4 @@
|
||||
export function validateFields(fieldsArray: (string | boolean | any[])[][]): (string | (() => void))[][] {
|
||||
export function validateFields(fieldsArray: ValueEntry[]): (string | (() => void))[][] {
|
||||
const errors = []
|
||||
let selectedGroup: number
|
||||
const numberRegex = /^[+]?([.]\d+|\d+([.]\d+)?)$/
|
||||
@ -23,18 +23,20 @@ export function validateFields(fieldsArray: (string | boolean | any[])[][]): (st
|
||||
if (field === "blockGroups" || (typeof field === "string" && field.includes("numberLabel"))) {
|
||||
if (!field.includes("numberLabel")) return
|
||||
// @ts-ignore
|
||||
const [elementValue, element, group, boolean] = value
|
||||
let [elementValue, element, group, boolean] = value
|
||||
element = element as HTMLElement
|
||||
if (!elementValue) return
|
||||
if (selectedGroup !== undefined) {
|
||||
if (group !== selectedGroup) errors.push(["block", wholeBlockInvalid])
|
||||
if (group !== String(selectedGroup)) errors.push(["block", wholeBlockInvalid])
|
||||
else validateNumber(elementValue, field, element)
|
||||
} else {
|
||||
//@ts-ignore
|
||||
selectedGroup = group
|
||||
validateNumber(elementValue, field, element)
|
||||
}
|
||||
return
|
||||
}
|
||||
value = value as any[]
|
||||
value = value
|
||||
let required = value[1]
|
||||
value = value[0]
|
||||
if (!required && !value) return
|
||||
@ -43,16 +45,16 @@ export function validateFields(fieldsArray: (string | boolean | any[])[][]): (st
|
||||
} 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_")) {
|
||||
} else if (field.includes("agreement_") && typeof value == "boolean") {
|
||||
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])
|
||||
} else if (field.includes("Email_") && typeof value == "string") {
|
||||
if (!emailRegex.test(value)) errors.push(["Ungültiges E-Mail-Format.", field])
|
||||
} else if (field.includes("date_") && typeof value == "string") {
|
||||
if (!dateRegex.test(value)) errors.push(["Ungültiges Datumsformat.", field])
|
||||
} else if (field.includes("times_") && typeof value == "string") {
|
||||
if (!timeRegex.test(value) && typeof value == "string") errors.push(["Ungültiges Zeitformat.", field])
|
||||
} else if (field.includes("Telefon_") && typeof value == "string") {
|
||||
if (!phoneRegex.test(value)) errors.push(["Ungültiges Telefonnummernformat.", field])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -14,4 +14,4 @@ export let navigation = writable<Navigation>()
|
||||
export let sites = writable<Sites>({})
|
||||
export let serviceNavigation = writable<Navigation>()
|
||||
export let banner = writable<Banner[]>([])
|
||||
export let temperature = writable<Temperature>()
|
||||
export let darkMode = writable<boolean>(false)
|
||||
|
@ -6,7 +6,6 @@
|
||||
let site: Site
|
||||
function getSelectedSite(path: string): Site | {} {
|
||||
let site = {}
|
||||
console.log($sites, "sites")
|
||||
if (Object.values($sites).length == 0) return {}
|
||||
Object.values($sites).forEach((element) => {
|
||||
if (element.path == "/" + path) site = element
|
||||
|
@ -27,6 +27,7 @@
|
||||
"connect-history-api-fallback": "^2.0.0",
|
||||
"esbuild": "^0.19.3",
|
||||
"esbuild-svelte": "^0.8.0",
|
||||
"fluent-svelte": "^1.6.0",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"less": "^4.2.0",
|
||||
"morgan": "^1.10.0",
|
||||
|
52
types/global.d.ts
vendored
52
types/global.d.ts
vendored
@ -127,10 +127,45 @@ interface VideoSwitch {
|
||||
link: string
|
||||
}
|
||||
|
||||
interface FormObj {
|
||||
formRows?: string[]
|
||||
index?: number
|
||||
formTitle?: string
|
||||
formValues?: Writable<FormValues>
|
||||
honey?: boolean
|
||||
agreement?: boolean
|
||||
}
|
||||
// Before transformation
|
||||
interface TempFormBefore {
|
||||
[rowName: string]: TempFormRowBefore
|
||||
}
|
||||
|
||||
interface TempFormRowBefore {
|
||||
[newKey: string]: [any, boolean, boolean]
|
||||
}
|
||||
|
||||
// After transformation
|
||||
interface TempFormAfter {
|
||||
[rowName: string]: Array<[string, [any, boolean, boolean]]>
|
||||
}
|
||||
|
||||
interface TempFormIndices {
|
||||
[rowName: string]: {
|
||||
[newKey: string]: number
|
||||
}
|
||||
}
|
||||
|
||||
type ValueEntry =
|
||||
| [string, [boolean | string | any, boolean]]
|
||||
| [string, [any, CustomHTMLElement, string | null, boolean]]
|
||||
|
||||
type ObjectEntry = [string, CustomHTMLElement]
|
||||
|
||||
interface FormRow {
|
||||
title?: string
|
||||
rowName: string
|
||||
columns: FormColumn[]
|
||||
showRowName: boolean
|
||||
}
|
||||
|
||||
interface Block {
|
||||
@ -174,7 +209,15 @@ interface FormColumn {
|
||||
emailNameTime: string
|
||||
emailNameTimes: string
|
||||
numberfieldOrder?: number
|
||||
showCheckboxGroup: boolean
|
||||
groupTitle: string
|
||||
checkboxes: Checkbox[]
|
||||
showDatePicker: boolean
|
||||
datePickerNotRequired: boolean
|
||||
datePickerProps: DatePickerProps
|
||||
datePickerEmailTitle: string
|
||||
}
|
||||
|
||||
interface CustomHTMLElement extends HTMLElement {
|
||||
checked?: boolean
|
||||
value?: any
|
||||
@ -182,6 +225,14 @@ interface CustomHTMLElement extends HTMLElement {
|
||||
getAttribute(attr: string): string | null
|
||||
}
|
||||
|
||||
interface DatePickerProps {
|
||||
allowedDateRanges: {
|
||||
from: string
|
||||
to: string
|
||||
}[]
|
||||
excludeDays: "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"
|
||||
}
|
||||
|
||||
interface FormValues {
|
||||
[key: string]: CustomHTMLElement
|
||||
blockGroups?: Set<number>
|
||||
@ -210,6 +261,7 @@ interface TextField {
|
||||
dateSelectNotRequired: boolean
|
||||
emailName: string
|
||||
textfieldOrder: string
|
||||
textTitle: string
|
||||
}
|
||||
|
||||
interface TeaserImage {
|
||||
|
27
yarn.lock
27
yarn.lock
@ -3642,6 +3642,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fluent-svelte@npm:^1.6.0":
|
||||
version: 1.6.0
|
||||
resolution: "fluent-svelte@npm:1.6.0"
|
||||
dependencies:
|
||||
focus-trap: ^6.7.3
|
||||
tabbable: ^5.2.1
|
||||
checksum: 1b2ac33343f6e34469e4af9b31e0d446b021b3b2cd64f91b5b010fcf045abdbf7bb5910b9bc4ad90bd5020cf4293e23f625acb01addede3806eb0325514b727d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"focus-trap@npm:^6.7.3":
|
||||
version: 6.9.4
|
||||
resolution: "focus-trap@npm:6.9.4"
|
||||
dependencies:
|
||||
tabbable: ^5.3.3
|
||||
checksum: 0b4cebcc11010bd9397731092bd59a981e838c710c6497374ba70571875a14ab27c0db7d60f36005ec01bdabc3b9cfeda11d30ddf5b8874596dcc95e18913b3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0":
|
||||
version: 1.15.2
|
||||
resolution: "follow-redirects@npm:1.15.2"
|
||||
@ -6533,6 +6552,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tabbable@npm:^5.2.1, tabbable@npm:^5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "tabbable@npm:5.3.3"
|
||||
checksum: 1aa56e1bb617cc10616c407f4e756f0607f3e2d30f9803664d70b85db037ca27e75918ed1c71443f3dc902e21dc9f991ce4b52d63a538c9b69b3218d3babcd70
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tar@npm:^6.1.11, tar@npm:^6.1.2":
|
||||
version: 6.1.12
|
||||
resolution: "tar@npm:6.1.12"
|
||||
@ -6567,6 +6593,7 @@ __metadata:
|
||||
cssnano: ^6.0.1
|
||||
esbuild: ^0.19.3
|
||||
esbuild-svelte: ^0.8.0
|
||||
fluent-svelte: ^1.6.0
|
||||
http-proxy-middleware: ^2.0.6
|
||||
less: ^4.2.0
|
||||
morgan: ^1.10.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user