new Routing
This commit is contained in:
parent
e97365b0b6
commit
5b16d988f5
10
app.vue
10
app.vue
@ -7,8 +7,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onBeforeUnmount } from 'vue'
|
import { onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { useMainStore } from '@/stores/main'
|
import { useMainStore } from '@/stores/main'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
mainStore.setDarkHeroBack(false)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Scroll- und Resize-Listener in den Lifecycle-Hooks registrieren
|
// Scroll- und Resize-Listener in den Lifecycle-Hooks registrieren
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
5
assets/images/DML_Logo.svg
Normal file
5
assets/images/DML_Logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 21 KiB |
@ -4,6 +4,7 @@
|
|||||||
v-for="(item, i) in items"
|
v-for="(item, i) in items"
|
||||||
:key="i"
|
:key="i"
|
||||||
class="accordion-item"
|
class="accordion-item"
|
||||||
|
:class="{ open: openIndex === i }"
|
||||||
>
|
>
|
||||||
<!-- Header --------------------------------------------------->
|
<!-- Header --------------------------------------------------->
|
||||||
<button
|
<button
|
||||||
@ -44,6 +45,18 @@ const toggle = (i: number) =>
|
|||||||
.accordion-item
|
.accordion-item
|
||||||
border-bottom: 1px solid $lightgrey
|
border-bottom: 1px solid $lightgrey
|
||||||
width: 100%
|
width: 100%
|
||||||
|
transition: .8s
|
||||||
|
|
||||||
|
&.open
|
||||||
|
background-image: linear-gradient(to right, $lightgrey, white)
|
||||||
|
padding: 1rem
|
||||||
|
|
||||||
|
.accordion-header
|
||||||
|
background: transparent
|
||||||
|
font-size: 120%
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background: transparent
|
||||||
|
|
||||||
.accordion-header
|
.accordion-header
|
||||||
all: unset
|
all: unset
|
||||||
@ -93,6 +106,16 @@ const toggle = (i: number) =>
|
|||||||
.accordion-content
|
.accordion-content
|
||||||
padding: 0 1rem 1rem
|
padding: 0 1rem 1rem
|
||||||
|
|
||||||
|
h3
|
||||||
|
font-size: 1rem
|
||||||
|
margin: 1.2rem 0 .6rem 0
|
||||||
|
p
|
||||||
|
font-size: 1rem
|
||||||
|
ul
|
||||||
|
li
|
||||||
|
line-height: 140%
|
||||||
|
margin-bottom: 1rem
|
||||||
|
|
||||||
// simple height-fade transition
|
// simple height-fade transition
|
||||||
.accordion-enter-from,
|
.accordion-enter-from,
|
||||||
.accordion-leave-to
|
.accordion-leave-to
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<button class="back-to-top" v-show="isVisible" @click="scrollToTop" aria-label="Zurück nach oben">
|
<button v-show="isVisible" class="back-to-top" aria-label="Zurück nach oben" @click="scrollToTop">
|
||||||
<span class="arrow-up"></span>
|
<span class="arrow-up"/>
|
||||||
</button>
|
</button>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div class="ctaBox">
|
<div class="ctaBox">
|
||||||
<h3>{{ headline }}</h3>
|
<h3>{{ headline }}</h3>
|
||||||
<p>{{ text }}</p>
|
<p>{{ text }}</p>
|
||||||
<button class="pinkBtn mt-1" @click.prevent="toggleContactBubble" role="button">
|
<button class="pinkBtn mt-1" role="button" @click.prevent="toggleContactBubble">
|
||||||
{{ buttonText }}
|
{{ buttonText }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -47,8 +47,8 @@
|
|||||||
<div v-if="screenWidth > 768" class="pt-3">
|
<div v-if="screenWidth > 768" class="pt-3">
|
||||||
<h3>{{ $t('contactForm.ourOffice') }}</h3>
|
<h3>{{ $t('contactForm.ourOffice') }}</h3>
|
||||||
<p class="address">
|
<p class="address">
|
||||||
{{ companyinfo.company }}<br />
|
{{ companyinfo.company }}<br >
|
||||||
{{ companyinfo.street }} <br />
|
{{ companyinfo.street }} <br >
|
||||||
{{ companyinfo.postalcode }} {{ companyinfo.city }}
|
{{ companyinfo.postalcode }} {{ companyinfo.city }}
|
||||||
</p>
|
</p>
|
||||||
<p class="aspProf">{{ $t('contactForm.yourcontactperson') }} <b>Sabrina Hennrich</b></p>
|
<p class="aspProf">{{ $t('contactForm.yourcontactperson') }} <b>Sabrina Hennrich</b></p>
|
||||||
@ -68,21 +68,21 @@
|
|||||||
<!-- Rechte Seite -->
|
<!-- Rechte Seite -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div v-if="!formSent">
|
<div v-if="!formSent">
|
||||||
<form @submit.prevent="submitForm" novalidate>
|
<form novalidate @submit.prevent="submitForm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name">{{ $t('contactForm.name') }}</label>
|
<label for="name">{{ $t('contactForm.name') }}</label>
|
||||||
<input
|
<input
|
||||||
id="name"
|
id="name"
|
||||||
class="form-control"
|
|
||||||
v-model="form.name"
|
v-model="form.name"
|
||||||
|
class="form-control"
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
required
|
required
|
||||||
autocomplete="name"
|
autocomplete="name"
|
||||||
@blur="validateName"
|
|
||||||
:aria-invalid="!!errors.name"
|
:aria-invalid="!!errors.name"
|
||||||
:aria-describedby="errors.name ? 'error-name' : null"
|
:aria-describedby="errors.name ? 'error-name' : null"
|
||||||
/>
|
@blur="validateName"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-if="errors.name"
|
v-if="errors.name"
|
||||||
id="error-name"
|
id="error-name"
|
||||||
@ -97,16 +97,16 @@
|
|||||||
<label for="email">{{ $t('contactForm.email') }}</label>
|
<label for="email">{{ $t('contactForm.email') }}</label>
|
||||||
<input
|
<input
|
||||||
id="email"
|
id="email"
|
||||||
class="form-control"
|
|
||||||
v-model="form.email"
|
v-model="form.email"
|
||||||
|
class="form-control"
|
||||||
type="email"
|
type="email"
|
||||||
name="email"
|
name="email"
|
||||||
required
|
required
|
||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
@blur="validateEmail"
|
|
||||||
:aria-invalid="!!errors.email"
|
:aria-invalid="!!errors.email"
|
||||||
:aria-describedby="errors.email ? 'error-email' : null"
|
:aria-describedby="errors.email ? 'error-email' : null"
|
||||||
/>
|
@blur="validateEmail"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-if="errors.email"
|
v-if="errors.email"
|
||||||
id="error-email"
|
id="error-email"
|
||||||
@ -121,15 +121,15 @@
|
|||||||
<label for="phone">{{ $t('contactForm.phone') }}</label>
|
<label for="phone">{{ $t('contactForm.phone') }}</label>
|
||||||
<input
|
<input
|
||||||
id="phone"
|
id="phone"
|
||||||
class="form-control"
|
|
||||||
v-model="form.phone"
|
v-model="form.phone"
|
||||||
|
class="form-control"
|
||||||
type="tel"
|
type="tel"
|
||||||
name="phone"
|
name="phone"
|
||||||
autocomplete="tel"
|
autocomplete="tel"
|
||||||
@blur="validatePhone"
|
|
||||||
:aria-invalid="!!errors.phone"
|
:aria-invalid="!!errors.phone"
|
||||||
:aria-describedby="errors.phone ? 'error-phone' : null"
|
:aria-describedby="errors.phone ? 'error-phone' : null"
|
||||||
/>
|
@blur="validatePhone"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
v-if="errors.phone"
|
v-if="errors.phone"
|
||||||
id="error-phone"
|
id="error-phone"
|
||||||
@ -144,19 +144,19 @@
|
|||||||
<label for="message">{{ $t('contactForm.message') }}</label>
|
<label for="message">{{ $t('contactForm.message') }}</label>
|
||||||
<textarea
|
<textarea
|
||||||
id="message"
|
id="message"
|
||||||
class="form-control mt-4"
|
|
||||||
v-model="form.message"
|
v-model="form.message"
|
||||||
|
class="form-control mt-4"
|
||||||
name="message"
|
name="message"
|
||||||
rows="4"
|
rows="4"
|
||||||
required
|
required
|
||||||
></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="smallText">
|
<p class="smallText">
|
||||||
<span class="check">✔</span>
|
<span class="check">✔</span>
|
||||||
{{ $t('contactForm.privacyInfotextBeforeLink') }}
|
{{ $t('contactForm.privacyInfotextBeforeLink') }}
|
||||||
<NuxtLinkLocale
|
<NuxtLinkLocale
|
||||||
:to="getRoute('privacy')"
|
:to="'privacy'"
|
||||||
:aria-label="$t('privacy')"
|
:aria-label="$t('privacy')"
|
||||||
>
|
>
|
||||||
{{ $t('contactForm.privacyInfotextLinkText') }}
|
{{ $t('contactForm.privacyInfotextLinkText') }}
|
||||||
@ -191,7 +191,7 @@ import { useMainStore } from '@/stores/main';
|
|||||||
import { ref, reactive, computed } from 'vue';
|
import { ref, reactive, computed } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
const { getRoute } = useI18nPages()
|
|
||||||
|
|
||||||
// i18n Setup
|
// i18n Setup
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// components/HeroBox.vue
|
// components/HeroBox.vue
|
||||||
<template>
|
<template>
|
||||||
<section class="heroBox" :aria-label="ariaLabel">
|
<section ref="heroBoxRef" class="heroBox" :aria-label="ariaLabel">
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
provider="strapi"
|
provider="strapi"
|
||||||
:src="image"
|
:src="image"
|
||||||
@ -13,6 +13,20 @@
|
|||||||
preload
|
preload
|
||||||
fetchpriority="high"
|
fetchpriority="high"
|
||||||
/>
|
/>
|
||||||
|
<!-- Optionales Overlay-Bild -->
|
||||||
|
<NuxtImg
|
||||||
|
v-if="overlayImage"
|
||||||
|
provider="strapi"
|
||||||
|
:src="overlayImage"
|
||||||
|
class="overlay-img"
|
||||||
|
:alt="overlayAltText"
|
||||||
|
:style="{
|
||||||
|
...overlayPosition,
|
||||||
|
width: typeof overlayWidth === 'number' ? overlayWidth + 'px' : overlayWidth,
|
||||||
|
transform: `translate3d(0, ${parallaxY}px, 0)`
|
||||||
|
}"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
<div class="container-10 content">
|
<div class="container-10 content">
|
||||||
<h1>{{ $t(content.headline1) }}</h1>
|
<h1>{{ $t(content.headline1) }}</h1>
|
||||||
<h2>{{ $t(content.headline2) }}</h2>
|
<h2>{{ $t(content.headline2) }}</h2>
|
||||||
@ -25,14 +39,78 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
defineProps({
|
// Parallax Overlay-Image
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { useMainStore } from '@/stores/main'
|
||||||
|
const mainStore = useMainStore()
|
||||||
|
const props = defineProps({
|
||||||
image: String,
|
image: String,
|
||||||
ariaLabel: String,
|
ariaLabel: String,
|
||||||
content: {
|
content: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
overlayImage: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
overlayAltText: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
overlayWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '200px'
|
||||||
|
},
|
||||||
|
darkBackground: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
overlayPosition: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
bottom: '0px',
|
||||||
|
right: '0px'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const parallaxY = ref(0)
|
||||||
|
const heroBoxRef = ref(null)
|
||||||
|
let targetY = 0
|
||||||
|
let animationFrame
|
||||||
|
const updateParallax = () => {
|
||||||
|
// Ease: Linear interpolation (lerp) zwischen aktuellem Wert und Zielwert
|
||||||
|
parallaxY.value += (targetY - parallaxY.value) * 0.1
|
||||||
|
animationFrame = requestAnimationFrame(updateParallax)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onScroll = () => {
|
||||||
|
targetY = window.scrollY * 0.3 // oder was dir gefällt
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateHeight = () => {
|
||||||
|
if (heroBoxRef.value) {
|
||||||
|
mainStore.setHeroBoxHeight(heroBoxRef.value.offsetHeight)
|
||||||
|
mainStore.setDarkHeroBack(props.darkBackground)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true })
|
||||||
|
updateParallax()
|
||||||
|
// HeroBoxHeight for Logo
|
||||||
|
|
||||||
|
updateHeight()
|
||||||
|
window.addEventListener('resize', updateHeight)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('scroll', onScroll)
|
||||||
|
cancelAnimationFrame(animationFrame)
|
||||||
|
window.removeEventListener('resize', updateHeight)
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
@ -71,13 +149,22 @@ defineProps({
|
|||||||
object-position: center top
|
object-position: center top
|
||||||
z-index: -1
|
z-index: -1
|
||||||
|
|
||||||
|
.overlay-img
|
||||||
|
position: absolute
|
||||||
|
bottom: 0
|
||||||
|
right: 0
|
||||||
|
z-index: 1
|
||||||
|
height: auto
|
||||||
|
max-height: 100%
|
||||||
|
object-fit: contain
|
||||||
|
|
||||||
.content, h1, h2, h3
|
.content, h1, h2, h3
|
||||||
position: relative
|
position: relative
|
||||||
z-index: 1
|
z-index: 2
|
||||||
|
|
||||||
h1, h2, h3
|
h1, h2, h3
|
||||||
color: white
|
color: white
|
||||||
z-index: 2
|
z-index: 3
|
||||||
line-height: 1.5
|
line-height: 1.5
|
||||||
max-width: 70%
|
max-width: 70%
|
||||||
@media (max-width: 768px)
|
@media (max-width: 768px)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="languageBox" v-if="locales.length >=2" @click="toggleOpen">
|
<div v-if="locales.length >=2" class="languageBox" @click="toggleOpen">
|
||||||
<div v-if="!open" class="current">{{ currentLanguage }}</div>
|
<div v-if="!open" class="current">{{ currentLanguage }}</div>
|
||||||
|
|
||||||
<transition name="slide">
|
<transition name="slide">
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="topSpace" v-if="currentPage">
|
<section v-if="currentPage" class="topSpace">
|
||||||
<div v-if="currentPage.pageSections[0].sectionText">
|
<div v-if="currentPage.pageSections[0].sectionText">
|
||||||
<div class="container content" v-html="htmlContent(currentPage.pageSections[0].sectionText)"></div>
|
<div class="container content" v-html="htmlContent(currentPage.pageSections[0].sectionText)"/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="topSpace" v-else>
|
<section v-else class="topSpace">
|
||||||
<h1>Seite nicht gefunden</h1>
|
<h1>Seite nicht gefunden</h1>
|
||||||
<p>Die angeforderte Seite existiert nicht.</p>
|
<p>Die angeforderte Seite existiert nicht.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
<section class="recommendations">
|
<section class="recommendations">
|
||||||
<!-- Vor dem Container: Welle oben -->
|
<!-- Vor dem Container: Welle oben -->
|
||||||
<svg class="sectionWave wave-top" :style="`height: ${waveHeight};top:-${waveHeight-2}`" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
<svg class="sectionWave wave-top" :style="`height: ${waveHeight};top:-${waveHeight-2}`" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#EEEBE5"></path>
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#EEEBE5"/>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>Das sagen andere Designer und Kreative über digimedialoop</h2>
|
<h2>Das sagen andere Designer und Kreative über digimedialoop</h2>
|
||||||
<div class="personBox" v-for="person, index in persons" :key="index" :class="person.active ? 'active' : ''" @click="setActive(index)">
|
<div v-for="person, index in persons" :key="index" class="personBox" :class="person.active ? 'active' : ''" @click="setActive(index)">
|
||||||
<img :src="person.image" alt="">
|
<img :src="person.image" alt="">
|
||||||
<div class="infoBox">
|
<div class="infoBox">
|
||||||
<h3>{{ person.name }}</h3>
|
<h3>{{ person.name }}</h3>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<!-- Nach dem Container: Spiegelwelle unten -->
|
<!-- Nach dem Container: Spiegelwelle unten -->
|
||||||
<svg class="sectionWave wave-bottom" :style="`height: ${waveHeight};bottom:-${waveHeight-2}`" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
<svg class="sectionWave wave-bottom" :style="`height: ${waveHeight};bottom:-${waveHeight-2}`" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#EEEBE5"></path>
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#EEEBE5"/>
|
||||||
</svg>
|
</svg>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
180
components/SchemaCoder.vue
Normal file
180
components/SchemaCoder.vue
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<template>
|
||||||
|
<div class="schema-typer">
|
||||||
|
<span class="token-tag"><<span class="token-tag-name">script</span> <span class="token-attr">type</span>=<span class="token-string">"application/ld+json"</span>></span><br >
|
||||||
|
<span
|
||||||
|
v-for="(line, lineIndex) in displayedLines"
|
||||||
|
:key="lineIndex"
|
||||||
|
class="code-line"
|
||||||
|
>
|
||||||
|
<template v-for="(segment, index) in line" :key="index">
|
||||||
|
<span :class="segment.class">{{ segment.text }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="(lineIndex === currentLine || (isTypingDone && lineIndex === displayedLines.length - 1)) && showCursor">
|
||||||
|
<span class="cursor">|</span>
|
||||||
|
</template>
|
||||||
|
<br >
|
||||||
|
</span>
|
||||||
|
<span class="token-tag"></<span class="token-tag-name">script</span>></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
const schema = `{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "HowTo",
|
||||||
|
"name": "So machen wir deine Website KI-kompatibel",
|
||||||
|
"description": "Wir optimieren deine Website gezielt für künstliche Intelligenz. Strukturiert, effizient und zukunftssicher.",
|
||||||
|
"step1": "Wir integrieren strukturierte Daten nach schema.org, damit KI-Systeme Inhalte korrekt interpretieren können.",
|
||||||
|
"step2": "Wir überarbeiten den Quellcode mit semantischem HTML und klaren Überschriften zur besseren maschinellen Lesbarkeit.",
|
||||||
|
"step3": "Wir stellen relevante Inhalte zusätzlich in maschinenfreundlichen Formaten wie JSON-LD oder über APIs bereit.",
|
||||||
|
"step4": "Wir sorgen für barrierefreie Gestaltung und klare Sprache, so verstehen auch KI-Sprachmodelle deine Inhalte besser.",
|
||||||
|
"step5": "Wir ergänzen deine Seiten mit Metadaten wie OpenGraph, Twitter Cards und Robots-Tags für optimalen Kontext.",
|
||||||
|
"estimatedTime": "ca. 45 Minuten Analyse + Umsetzung je nach Umfang",
|
||||||
|
"image": "/images/ki-optimierung.jpg"
|
||||||
|
}`
|
||||||
|
|
||||||
|
function parseLine(line) {
|
||||||
|
const segments = []
|
||||||
|
const regex = /("[^"]+":)|("[^"]+")|(\d+)|(true|false|null)|(\s+|[{}[\],:])/g
|
||||||
|
let match
|
||||||
|
let lastIndex = 0
|
||||||
|
|
||||||
|
while ((match = regex.exec(line)) !== null) {
|
||||||
|
const start = match.index
|
||||||
|
if (start > lastIndex) {
|
||||||
|
segments.push({ text: line.slice(lastIndex, start), class: 'token-text' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const [matched, key, str, num, bool, symbol] = match
|
||||||
|
let cls = 'token-text'
|
||||||
|
if (key) cls = 'token-key'
|
||||||
|
else if (str) cls = 'token-string'
|
||||||
|
else if (num) cls = 'token-number'
|
||||||
|
else if (bool) cls = 'token-boolean'
|
||||||
|
else if (symbol) cls = 'token-text'
|
||||||
|
|
||||||
|
segments.push({ text: matched, class: cls })
|
||||||
|
lastIndex = start + matched.length
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIndex < line.length) {
|
||||||
|
segments.push({ text: line.slice(lastIndex), class: 'token-text' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments
|
||||||
|
}
|
||||||
|
|
||||||
|
const lines = schema.split('\n').map(parseLine)
|
||||||
|
const displayedLines = ref([])
|
||||||
|
const showCursor = ref(true)
|
||||||
|
const currentLine = ref(0)
|
||||||
|
const isTypingDone = ref(false)
|
||||||
|
|
||||||
|
const startTyping = () => {
|
||||||
|
let lineIndex = 0
|
||||||
|
let charIndex = 0
|
||||||
|
displayedLines.value.push([])
|
||||||
|
|
||||||
|
const typeChar = () => {
|
||||||
|
if (lineIndex >= lines.length) {
|
||||||
|
isTypingDone.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const segment = lines[lineIndex][charIndex]
|
||||||
|
if (segment) {
|
||||||
|
displayedLines.value[lineIndex].push(segment)
|
||||||
|
charIndex++
|
||||||
|
} else {
|
||||||
|
lineIndex++
|
||||||
|
charIndex = 0
|
||||||
|
currentLine.value = lineIndex
|
||||||
|
if (lineIndex < lines.length) displayedLines.value.push([])
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(typeChar, Math.random() * 80 + 40)
|
||||||
|
}
|
||||||
|
|
||||||
|
typeChar()
|
||||||
|
setInterval(() => (showCursor.value = !showCursor.value), 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const observer = new IntersectionObserver(([entry]) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
observer.disconnect()
|
||||||
|
startTyping()
|
||||||
|
}
|
||||||
|
}, { threshold: 0.3 })
|
||||||
|
|
||||||
|
const el = document.querySelector('.schema-typer')
|
||||||
|
if (el) observer.observe(el)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.schema-typer
|
||||||
|
background-color: #1e1e1e
|
||||||
|
padding: 1.5rem
|
||||||
|
margin: 2rem
|
||||||
|
border-radius: 0.5rem
|
||||||
|
font-family: monospace
|
||||||
|
font-size: 0.7rem
|
||||||
|
color: #ffffff
|
||||||
|
overflow-x: auto
|
||||||
|
overflow-y: auto
|
||||||
|
line-height: 1.4
|
||||||
|
height: auto
|
||||||
|
min-height: 450px
|
||||||
|
width: 400px
|
||||||
|
transform: rotate(6deg)
|
||||||
|
box-shadow: -3px 3px 6px 4px grey
|
||||||
|
|
||||||
|
span
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
.code-line
|
||||||
|
display: block
|
||||||
|
line-height: 1.2
|
||||||
|
|
||||||
|
.token-tag
|
||||||
|
color: #569cd6
|
||||||
|
|
||||||
|
.token-tag-name
|
||||||
|
color: #4ec9b0
|
||||||
|
|
||||||
|
.token-attr
|
||||||
|
color: #c586c0
|
||||||
|
|
||||||
|
.token-key
|
||||||
|
color: #9cdcfe
|
||||||
|
margin-left: 1rem
|
||||||
|
|
||||||
|
.token-string
|
||||||
|
color: #ce9178
|
||||||
|
|
||||||
|
.token-number
|
||||||
|
color: #b5cea8
|
||||||
|
|
||||||
|
.token-boolean
|
||||||
|
color: #dcdcaa
|
||||||
|
|
||||||
|
.token-text
|
||||||
|
color: #d4d4d4
|
||||||
|
margin-left: .2rem
|
||||||
|
|
||||||
|
.cursor
|
||||||
|
display: inline-block
|
||||||
|
width: 1ch
|
||||||
|
background-color: white
|
||||||
|
animation: blink 1s steps(2, start) infinite
|
||||||
|
|
||||||
|
@keyframes blink
|
||||||
|
to
|
||||||
|
visibility: hidden
|
||||||
|
</style>
|
||||||
|
|
||||||
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sideBarNaviSlider"
|
<div
|
||||||
|
class="sideBarNaviSlider"
|
||||||
:class="{ 'slide-in': showSideBar }"
|
:class="{ 'slide-in': showSideBar }"
|
||||||
@click="navigate">
|
@click="navigate">
|
||||||
<slot></slot>
|
<slot/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
import { useI18n } from 'vue-i18n'
|
/* import { useI18n } from 'vue-i18n'
|
||||||
import { i18nPages } from '@/i18n/i18n-pages'
|
import { i18nPages } from '@/i18n/i18n-pages'
|
||||||
|
|
||||||
export function useI18nPages () {
|
export function useI18nPages () {
|
||||||
@ -31,3 +31,4 @@ export function useI18nPages () {
|
|||||||
getArticleLink
|
getArticleLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
@ -7,7 +7,7 @@ export const i18nPages = {
|
|||||||
es: '/inicio',
|
es: '/inicio',
|
||||||
tr: '/anasayfa'
|
tr: '/anasayfa'
|
||||||
},
|
},
|
||||||
webagency: {
|
webagency: {
|
||||||
de: '/webagentur',
|
de: '/webagentur',
|
||||||
en: '/webagency',
|
en: '/webagency',
|
||||||
fr: '/agence-web',
|
fr: '/agence-web',
|
||||||
@ -15,7 +15,7 @@ export const i18nPages = {
|
|||||||
es: '/agencia-web',
|
es: '/agencia-web',
|
||||||
tr: '/web-ajansi'
|
tr: '/web-ajansi'
|
||||||
},
|
},
|
||||||
services: {
|
services: {
|
||||||
de: '/leistungen',
|
de: '/leistungen',
|
||||||
en: '/services',
|
en: '/services',
|
||||||
fr: '/services',
|
fr: '/services',
|
||||||
@ -23,23 +23,39 @@ export const i18nPages = {
|
|||||||
es: '/servicios',
|
es: '/servicios',
|
||||||
tr: '/hizmetler'
|
tr: '/hizmetler'
|
||||||
},
|
},
|
||||||
'services/accessibility': {
|
'services-accessibility': {
|
||||||
de: '/leistungen/barrierefreiheit',
|
de: '/leistungen/barrierefreie-webseiten',
|
||||||
en: '/services/accessibility',
|
en: '/services/accessible-websites',
|
||||||
fr: '/services/accessibilite',
|
fr: '/services/sites-accessibles',
|
||||||
it: '/servizi/accessibilita',
|
it: '/servizi/siti-accessibili',
|
||||||
es: '/servicios/accesibilidad',
|
es: '/servicios/sitios-accesibles',
|
||||||
tr: '/hizmetler/erisilebilirlik'
|
tr: '/hizmetler/erisilebilir-websiteler'
|
||||||
},
|
},
|
||||||
'services/seo': {
|
'services-seo': {
|
||||||
de: '/leistungen/barrierefreiheit',
|
de: '/leistungen/suchmaschinenoptimierung',
|
||||||
en: '/services/accessibility',
|
en: '/services/search-engine-optimization',
|
||||||
fr: '/services/accessibilite',
|
fr: '/services/optimisation-pour-moteurs-de-recherche',
|
||||||
it: '/servizi/accessibilita',
|
it: '/servizi/ottimizzazione-per-motori-di-ricerca',
|
||||||
es: '/servicios/accesibilidad',
|
es: '/servicios/optimizacion-en-buscadores',
|
||||||
tr: '/hizmetler/erisilebilirlik'
|
tr: '/hizmetler/arama-motoru-optimizasyonu'
|
||||||
},
|
},
|
||||||
references: {
|
'services-cms': {
|
||||||
|
de: '/leistungen/headless-cms',
|
||||||
|
en: '/services/headless-cms',
|
||||||
|
fr: '/services/headless-cms',
|
||||||
|
it: '/servizi/headless-cms',
|
||||||
|
es: '/servicios/headless-cms',
|
||||||
|
tr: '/hizmetler/headless-cms'
|
||||||
|
},
|
||||||
|
'services-ai': {
|
||||||
|
de: '/leistungen/ki-kompatible-webseiten',
|
||||||
|
en: '/services/ai-compatible-websites',
|
||||||
|
fr: '/services/sites-compatibles-ia',
|
||||||
|
it: '/servizi/siti-compatibili-ai',
|
||||||
|
es: '/servicios/sitios-compatibles-ai',
|
||||||
|
tr: '/hizmetler/ai-uyumlu-websiteler'
|
||||||
|
},
|
||||||
|
references: {
|
||||||
de: '/referenzen',
|
de: '/referenzen',
|
||||||
en: '/references',
|
en: '/references',
|
||||||
fr: '/références',
|
fr: '/références',
|
||||||
@ -47,7 +63,7 @@ export const i18nPages = {
|
|||||||
es: '/referencias',
|
es: '/referencias',
|
||||||
tr: '/referanslar'
|
tr: '/referanslar'
|
||||||
},
|
},
|
||||||
imprint: {
|
imprint: {
|
||||||
de: '/impressum',
|
de: '/impressum',
|
||||||
en: '/imprint',
|
en: '/imprint',
|
||||||
fr: '/mentions-legales',
|
fr: '/mentions-legales',
|
||||||
@ -55,17 +71,15 @@ export const i18nPages = {
|
|||||||
es: '/aviso-legal',
|
es: '/aviso-legal',
|
||||||
tr: '/künye'
|
tr: '/künye'
|
||||||
},
|
},
|
||||||
'projekt___link': {
|
'project-link': {
|
||||||
paths: {
|
de: '/projekt/[link]',
|
||||||
de: '/projekt/:link',
|
en: '/project/[link]',
|
||||||
en: '/projekt/:link',
|
fr: '/projet/[link]',
|
||||||
fr: '/projekt/:link',
|
it: '/progetto/[link]',
|
||||||
it: '/projekt/:link',
|
es: '/proyecto/[link]',
|
||||||
es: '/projekt/:link',
|
tr: '/proje/[link]'
|
||||||
tr: '/projekt/:link'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
designer: {
|
designer: {
|
||||||
de: '/designer',
|
de: '/designer',
|
||||||
en: '/designers',
|
en: '/designers',
|
||||||
fr: '/createurs',
|
fr: '/createurs',
|
||||||
@ -73,7 +87,7 @@ export const i18nPages = {
|
|||||||
es: '/disenadores',
|
es: '/disenadores',
|
||||||
tr: '/tasarimcilar'
|
tr: '/tasarimcilar'
|
||||||
},
|
},
|
||||||
privacy: {
|
privacy: {
|
||||||
de: '/datenschutz',
|
de: '/datenschutz',
|
||||||
en: '/privacy',
|
en: '/privacy',
|
||||||
fr: '/confidentialite',
|
fr: '/confidentialite',
|
||||||
@ -81,7 +95,7 @@ export const i18nPages = {
|
|||||||
es: '/privacidad',
|
es: '/privacidad',
|
||||||
tr: '/gizlilik'
|
tr: '/gizlilik'
|
||||||
},
|
},
|
||||||
terms: {
|
terms: {
|
||||||
de: '/agb',
|
de: '/agb',
|
||||||
en: '/terms',
|
en: '/terms',
|
||||||
fr: '/conditions',
|
fr: '/conditions',
|
||||||
@ -89,7 +103,7 @@ export const i18nPages = {
|
|||||||
es: '/condiciones',
|
es: '/condiciones',
|
||||||
tr: '/kosullar'
|
tr: '/kosullar'
|
||||||
},
|
},
|
||||||
magazin: {
|
magazin: {
|
||||||
de: '/wissenswertes',
|
de: '/wissenswertes',
|
||||||
en: '/magazine',
|
en: '/magazine',
|
||||||
fr: '/magazine',
|
fr: '/magazine',
|
||||||
@ -97,14 +111,12 @@ export const i18nPages = {
|
|||||||
es: '/revista',
|
es: '/revista',
|
||||||
tr: '/dergi'
|
tr: '/dergi'
|
||||||
},
|
},
|
||||||
'artikel___link': {
|
'article-link': {
|
||||||
paths: {
|
de: '/artikel/[link]',
|
||||||
de: '/artikel/:link',
|
en: '/article/[link]',
|
||||||
en: '/artikel/:link',
|
fr: '/article/[link]',
|
||||||
fr: '/artikel/:link',
|
it: '/articolo/[link]',
|
||||||
it: '/artikel/:link',
|
es: '/articulo/[link]',
|
||||||
es: '/artikel/:link',
|
tr: '/makale/[link]'
|
||||||
tr: '/artikel/:link'
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
@ -4,6 +4,10 @@
|
|||||||
"upperBavaria": "Oberbayern",
|
"upperBavaria": "Oberbayern",
|
||||||
"webagency": "Webagentur",
|
"webagency": "Webagentur",
|
||||||
"services": "Leistungen",
|
"services": "Leistungen",
|
||||||
|
"menuAi": "KI-kompatible Webseiten",
|
||||||
|
"menuCms": "Headless Content-Management-System (CMS)",
|
||||||
|
"menuAccessibility": "Barrierefeies Webdesign",
|
||||||
|
"menuSEO": "Suchmaschinen-Optimierung (SEO)",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"references": "Referenzen",
|
"references": "Referenzen",
|
||||||
"referenceoverview": "Referenzübersicht",
|
"referenceoverview": "Referenzübersicht",
|
||||||
@ -51,7 +55,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"faqBox": {
|
"faqBox": {
|
||||||
"questions": "Fragen?",
|
"questions": "Weitere Fragen?",
|
||||||
"faqsDefault": "Häufig gestellte Fragen (FAQs)",
|
"faqsDefault": "Häufig gestellte Fragen (FAQs)",
|
||||||
"btnDefault": "Sprechen Sie uns gerne an!"
|
"btnDefault": "Sprechen Sie uns gerne an!"
|
||||||
},
|
},
|
||||||
@ -166,14 +170,71 @@
|
|||||||
"hero": {
|
"hero": {
|
||||||
"headline1": "Barrierefeies Webdesign",
|
"headline1": "Barrierefeies Webdesign",
|
||||||
"headline2": "Zugänglichkeit für Mensch und Maschine nach den Standards WCAG und BITV",
|
"headline2": "Zugänglichkeit für Mensch und Maschine nach den Standards WCAG und BITV",
|
||||||
"headline3": "Verständlich, nutzbar und robust, für eine inklusive und zukunftssichere Webseite"
|
"headline3": "Verständlich, nutzbar und robust, für eine inklusive und zukunftssichere Webseite",
|
||||||
|
"ariaLabel": "Barrierefreies Webdesign"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"hero": {
|
"hero": {
|
||||||
"headline1": "Suchmaschinen-Optimierung",
|
"headline1": "Suchmaschinen-Optimierung",
|
||||||
"headline2": "mit strukturierten Daten, Meta-Tags und semantischem HTML",
|
"headline2": "mit strukturierten Daten, Meta-Tags und semantischem HTML",
|
||||||
"headline3": "Mehr Sichbarkeit durch technische Exzellenz!"
|
"headline3": "Mehr Sichbarkeit durch technische Exzellenz!",
|
||||||
|
"ariaLabel": "Suchmaschinen-Optimierung"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cms": {
|
||||||
|
"hero": {
|
||||||
|
"headline1": "Flexibles Headless Content-Management-System",
|
||||||
|
"headline2": "mit strukturierten Daten, Meta-Tags und semantischem HTML",
|
||||||
|
"headline3": "Mehr Sichbarkeit durch technische Exzellenz",
|
||||||
|
"ariaLabel": "Content-Management-System"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ai": {
|
||||||
|
"hero": {
|
||||||
|
"ariaLabel": "Hero-Bereich: KI-kompatible Webseiten",
|
||||||
|
"headline1": "KI-kompatible Webseiten",
|
||||||
|
"headline2": "Strukturierte, maschinenlesbare Inhalte für eine neue Generation digitaler Assistenten.",
|
||||||
|
"headline3": "Bereit für Chatbots, Sprachsuche und generative KI-Systeme wie ChatGPT & Co.?"
|
||||||
|
},
|
||||||
|
"whyAI": {
|
||||||
|
"headline": "Warum KI-Kompatibilität im Web immer wichtiger wird",
|
||||||
|
"text1": "KI-Assistenten greifen heutzutage nicht nur auf strukturierte Inhalte im Web zu, um präzise Antworten zu liefern, sondern auch, um direkt mit Webseiten zu interagieren. Sie nehmen Buchungen vor, lösen Bestellungen aus oder vereinbaren Termine.",
|
||||||
|
"text2": "Wer sicherstellen möchte, dass die eigene Webseite dabei berücksichtigt wird, muss eine technische Grundlage schaffen, um Sichtbarkeit zu sein und Interaktion zu ermöglichen."
|
||||||
|
},
|
||||||
|
"targetGroup": {
|
||||||
|
"headline": "Für wen lohnt sich eine KI-kompatible Webseite?",
|
||||||
|
"point1_headline": "Content-Ersteller & Medienunternehmen",
|
||||||
|
"point1_description": "Maximieren Sie Ihre Reichweite, indem KI Ihre Inhalte intelligent versteht und verteilt.",
|
||||||
|
"point2_headline": "Onlineshop-Betreiber",
|
||||||
|
"point2_description": "Ermöglichen Sie Kunden, Ihre Produkte per Sprachbefehl zu finden und direkt zu kaufen.",
|
||||||
|
"point3_headline": "Dienstleister & Freiberufler",
|
||||||
|
"point3_description": "Werden Sie per Sprachsuche schnell gefunden und bieten Sie unkomplizierte Terminbuchungen an.",
|
||||||
|
"point4_headline": "Unternehmen mit digitaler Wachstumsstrategie",
|
||||||
|
"point4_description": "Bleiben Sie auf Suchmaschinen und bei KI-Assistenten an der Spitze der Sichtbarkeit."
|
||||||
|
},
|
||||||
|
"howItWorks": {
|
||||||
|
"headline": "Was macht eine Webseite KI-kompatibel?",
|
||||||
|
"pretext": "Damit künstliche Intelligenzen Webseiten richtig verstehen und Inhalte optimal nutzen können, braucht es mehr als nur gute Texte und schönes Design. Es braucht eine klar strukturierte, technisch saubere Basis.",
|
||||||
|
"point1": "Strukturierte Daten via Schema.org & JSON-LD",
|
||||||
|
"point2": "Semantisches HTML für kontextuelles Verständnis",
|
||||||
|
"point3": "Logische Inhalts-Hierarchien",
|
||||||
|
"point4": "Optimierung für Sprachsuche & Featured Snippets",
|
||||||
|
"point5": "Content-Strategien für Large Language Models (LLMs)",
|
||||||
|
"point6": "Maschinenlesbare Metadaten & Open Graph Tags",
|
||||||
|
"posttext": "All diese maschinenlesbaren Strukturen integrieren wir direkt im Code. Ohne Plugins, ohne Umwege. So bleiben Performance und Kontrolle erhalten und die Basis der Website ist von Grund auf KI-optimiert."
|
||||||
|
},
|
||||||
|
"howWeDo": {
|
||||||
|
"headline": "Wie wir KI-Kompatibilität mit Nuxt + Strapi umsetzen",
|
||||||
|
"text": "Unser Headless-Ansatz mit Nuxt 3 und Strapi ermöglicht volle Kontrolle über Metadaten, Struktur und Performance.",
|
||||||
|
"point1": "Integration strukturierter Daten direkt im CMS",
|
||||||
|
"point2": "SEO-optimiertes Rendering durch SSR & SSG",
|
||||||
|
"point3": "Zentrale Steuerung aller Meta- und JSON-LD-Daten",
|
||||||
|
"point4": "Flexible Inhaltsmodelle für semantischen Aufbau",
|
||||||
|
"point5": "Anpassung für Chatbots, Sprachassistenten und KI-Crawler"
|
||||||
|
},
|
||||||
|
"faq": {
|
||||||
|
"headline": "Weitere Fragen zum Thema künstliche Intelligenz im Webdesign"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -17,11 +17,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useMainStore } from '@/stores/main'
|
||||||
|
const mainStore = useMainStore()
|
||||||
import { usePageMeta } from '~/composables/usePageMeta'
|
import { usePageMeta } from '~/composables/usePageMeta'
|
||||||
|
|
||||||
usePageMeta()
|
usePageMeta()
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
mainStore.setDarkHeroBack(false) // Standardmäßig false
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@ -168,19 +173,22 @@ main
|
|||||||
|
|
||||||
.check
|
.check
|
||||||
list-style: none
|
list-style: none
|
||||||
padding: .2rem 1rem
|
padding: 0 0 1rem 1rem
|
||||||
margin: 0
|
|
||||||
|
|
||||||
li
|
li
|
||||||
position: relative
|
position: relative
|
||||||
padding-left: 1.5em
|
padding-left: 2rem
|
||||||
margin: .8em 0
|
font-size: 1rem
|
||||||
|
margin-bottom: 1rem
|
||||||
&::before
|
|
||||||
content: "\2713"
|
&::before
|
||||||
position: absolute
|
content: "✔"
|
||||||
left: 0
|
color: $primaryColor
|
||||||
color: $primaryColor
|
font-weight: bold
|
||||||
|
position: absolute
|
||||||
|
font-size: 1.4rem
|
||||||
|
left: 0
|
||||||
|
top: 0
|
||||||
|
|
||||||
section
|
section
|
||||||
margin-bottom: 5vh
|
margin-bottom: 5vh
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="article" v-if="article">
|
<div v-if="article" class="article">
|
||||||
<SideBarNaviSlider link="/wissenswertes">
|
<SideBarNaviSlider link="/wissenswertes">
|
||||||
{{ $t('pages.article.artikelUebersicht') }}
|
{{ $t('pages.article.artikelUebersicht') }}
|
||||||
</SideBarNaviSlider>
|
</SideBarNaviSlider>
|
||||||
@ -30,12 +30,12 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="articleBox container">
|
<section class="articleBox container">
|
||||||
<div v-html="htmlContent(article.content)" class="content"></div>
|
<div class="content" v-html="htmlContent(article.content)"/>
|
||||||
<button
|
<button
|
||||||
@click.prevent="toggleContactBubble"
|
|
||||||
class="pinkBtn"
|
class="pinkBtn"
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="Kontakt aufnehmen"
|
aria-label="Kontakt aufnehmen"
|
||||||
|
@click.prevent="toggleContactBubble"
|
||||||
>
|
>
|
||||||
{{ $t('pages.article.kontaktieren') }}
|
{{ $t('pages.article.kontaktieren') }}
|
||||||
</button>
|
</button>
|
||||||
@ -49,6 +49,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
name: 'article-link'
|
||||||
|
})
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { useMainStore } from '@/stores/main'
|
import { useMainStore } from '@/stores/main'
|
||||||
@ -37,18 +37,18 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<p><b>Du bleibst der kreative Kopf!</b><br>
|
<p><b>Du bleibst der kreative Kopf!</b><br>
|
||||||
Ich sorge dafür, dass dein Design genauso im Web erscheint, wie du es geplant hast – mit Top-Performance & perfekter technischer Umsetzung.</p>
|
Ich sorge dafür, dass dein Design genauso im Web erscheint, wie du es geplant hast – mit Top-Performance & perfekter technischer Umsetzung.</p>
|
||||||
<button class="pinkBtn" @click.prevent="toggleContactBubble" role="button">Lass uns kennenlernen</button>
|
<button class="pinkBtn" role="button" @click.prevent="toggleContactBubble">Lass uns kennenlernen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section class="deviceCheck" v-if="false">
|
<section v-if="false" class="deviceCheck">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<p class="supheadlinePink">Responsive Check</p>
|
<p class="supheadlinePink">Responsive Check</p>
|
||||||
<h2>Wie sieht deine Webseite auf den verschiedenen Bildschirmbreiten aus?</h2>
|
<h2>Wie sieht deine Webseite auf den verschiedenen Bildschirmbreiten aus?</h2>
|
||||||
<h3>Probiers einfach aus!</h3>
|
<h3>Probiers einfach aus!</h3>
|
||||||
<input type="text" placeholder="https://www.deinewebseite.de" v-model="weblink" @keyup.enter="updateIframe">
|
<input v-model="weblink" type="text" placeholder="https://www.deinewebseite.de" @keyup.enter="updateIframe">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<svg v-if="desk" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 450">
|
<svg v-if="desk" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 450">
|
||||||
@ -81,7 +81,7 @@
|
|||||||
<rect id="deskScreenBlank" x="46" y="47.5" width="409.5" height="221.5" transform="matrix(1,0,0,1,0,0)" fill="rgb(0,0,0)"/>
|
<rect id="deskScreenBlank" x="46" y="47.5" width="409.5" height="221.5" transform="matrix(1,0,0,1,0,0)" fill="rgb(0,0,0)"/>
|
||||||
<g>
|
<g>
|
||||||
<foreignObject v-if="isValidUrl(weblink)" id="deskScreen" x="46" y="47.5" width="409.5" height="221.5">
|
<foreignObject v-if="isValidUrl(weblink)" id="deskScreen" x="46" y="47.5" width="409.5" height="221.5">
|
||||||
<iframe ref="iframeRef" :src="weblink" frameborder="0"></iframe>
|
<iframe ref="iframeRef" :src="weblink" frameborder="0"/>
|
||||||
</foreignObject>
|
</foreignObject>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@ -119,19 +119,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<Recommendations />
|
<Recommendations />
|
||||||
<section class="contrastCalcLink" v-if="false">
|
<section v-if="false" class="contrastCalcLink">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<img src="https://strapi.digimedialoop.de/uploads/wcag_kontrastrechner_77abf9d9be.png" alt="kontrast check" class="imgRight">
|
<img src="https://strapi.digimedialoop.de/uploads/wcag_kontrastrechner_77abf9d9be.png" alt="kontrast check" class="imgRight">
|
||||||
<p class="supheadlinePink">Barrierefreies Webdesign</p>
|
<p class="supheadlinePink">Barrierefreies Webdesign</p>
|
||||||
<h2>Hat Dein Design den richtigen Kontrast?</h2>
|
<h2>Hat Dein Design den richtigen Kontrast?</h2>
|
||||||
<p>Mit dem praktischen Kontrastchecker kannst Du herausfinden, ob die Schrift und der Hintergrund in Deinem Design den WCAG_Richtlinien entsprechen. So stellst Du sicher, dass Dein Design für alle gut lesbar ist.</p>
|
<p>Mit dem praktischen Kontrastchecker kannst Du herausfinden, ob die Schrift und der Hintergrund in Deinem Design den WCAG_Richtlinien entsprechen. So stellst Du sicher, dass Dein Design für alle gut lesbar ist.</p>
|
||||||
<button class="mintBtn" @click.prevent="navigateTo('/toolbox/kontrastchecker')"
|
<button
|
||||||
role="button"
|
class="mintBtn" role="button"
|
||||||
aria-label="Zum Kontrastchecker">Jetzt kostenlos Konstrast prüfen</button>
|
aria-label="Zum Kontrastchecker"
|
||||||
|
@click.prevent="navigateTo('/toolbox/kontrastchecker')">Jetzt kostenlos Konstrast prüfen</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<FAQArea
|
<FAQArea
|
||||||
pageLink="/webentwicklung-fuer-designer-und-mediengestalter"
|
page-link="/webentwicklung-fuer-designer-und-mediengestalter"
|
||||||
headline="Wichtige Antworten zur Zusammenarbeit im Überblick für Dich"
|
headline="Wichtige Antworten zur Zusammenarbeit im Überblick für Dich"
|
||||||
button="Dann lass uns quatschen!"
|
button="Dann lass uns quatschen!"
|
||||||
/>
|
/>
|
||||||
@ -139,11 +140,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
|
import { useMainStore } from '@/stores/main';
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
name: 'designer'
|
name: 'designer'
|
||||||
})
|
})
|
||||||
import { ref, onMounted, onUnmounted, nextTick } from "vue";
|
|
||||||
import { useMainStore } from '@/stores/main';
|
|
||||||
// Lade diese Komponente synchron wegen SEO
|
// Lade diese Komponente synchron wegen SEO
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
headline2: 'pages.services.hero.headline2',
|
headline2: 'pages.services.hero.headline2',
|
||||||
headline3: 'pages.services.hero.headline3'
|
headline3: 'pages.services.hero.headline3'
|
||||||
}"
|
}"
|
||||||
|
:dark-background="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section class="explainBox" :aria-label="$t('pages.services.explain.ariaLabel')">
|
<section class="explainBox" :aria-label="$t('pages.services.explain.ariaLabel')">
|
||||||
@ -32,7 +33,9 @@
|
|||||||
<li>{{ $t('pages.services.explain.bullet4') }}</li>
|
<li>{{ $t('pages.services.explain.bullet4') }}</li>
|
||||||
<li>{{ $t('pages.services.explain.bullet5') }}</li>
|
<li>{{ $t('pages.services.explain.bullet5') }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<button @click="navigateTo(localePath('accessibility'))">Informationen zu barrierefreien Webseiten</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
@ -88,6 +91,10 @@ class="pinkBtn mt-3"
|
|||||||
import { useMainStore } from '@/stores/main';
|
import { useMainStore } from '@/stores/main';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { useRuntimeConfig, navigateTo } from '#app'
|
||||||
|
import { useLocalePath } from '#i18n'
|
||||||
|
|
||||||
|
const localePath = useLocalePath()
|
||||||
|
|
||||||
const mainStore = useMainStore();
|
const mainStore = useMainStore();
|
||||||
const { customers } = storeToRefs(mainStore);
|
const { customers } = storeToRefs(mainStore);
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
class="article"
|
class="article"
|
||||||
>
|
>
|
||||||
|
|
||||||
<NuxtLink :to="getArticleLink(article.slug)" class="article-link">
|
<NuxtLinkLocale :to="localePath({ name: 'article-link', params: { link: article.slug } })" class="article-link">
|
||||||
<div class="image-wrapper">
|
<div class="image-wrapper">
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
v-if="article.image?.url"
|
v-if="article.image?.url"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<button class="mintBtn">{{ $t('pages.magazin.readmore') }}</button>
|
<button class="mintBtn">{{ $t('pages.magazin.readmore') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLinkLocale>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -42,14 +42,14 @@
|
|||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch } from 'vue'
|
import { watch } from 'vue'
|
||||||
import { useMainStore } from '@/stores/main'
|
import { useMainStore } from '@/stores/main'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useLocalePath } from '#i18n'
|
||||||
|
const localePath = useLocalePath()
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { articles, cmsUrl } = storeToRefs(mainStore)
|
const { articles } = storeToRefs(mainStore)
|
||||||
|
|
||||||
const { getArticleLink } = useI18nPages()
|
|
||||||
|
|
||||||
const truncateText = (text: string, length = 200) =>
|
const truncateText = (text: string, length = 200) =>
|
||||||
text?.length > length ? text.substring(0, length) + '…' : text
|
text?.length > length ? text.substring(0, length) + '…' : text
|
||||||
@ -58,6 +58,7 @@ const currentDomain = typeof window !== 'undefined'
|
|||||||
? window.location.origin
|
? window.location.origin
|
||||||
: 'https://www.digimedialoop.de'
|
: 'https://www.digimedialoop.de'
|
||||||
|
|
||||||
|
|
||||||
// SEO: JSON-LD für Artikelübersicht
|
// SEO: JSON-LD für Artikelübersicht
|
||||||
watch(articles, (newVal) => {
|
watch(articles, (newVal) => {
|
||||||
if (newVal?.length) {
|
if (newVal?.length) {
|
||||||
|
|||||||
@ -46,8 +46,8 @@
|
|||||||
:src="img.url"
|
:src="img.url"
|
||||||
:alt="img.alternativeText"
|
:alt="img.alternativeText"
|
||||||
provider="strapi"
|
provider="strapi"
|
||||||
@click="setCurrentImage(img)"
|
|
||||||
:class="{ active: currentImage?.url === img.url }"
|
:class="{ active: currentImage?.url === img.url }"
|
||||||
|
@click="setCurrentImage(img)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="col-lg-8 pt-4">
|
<div class="col-lg-8 pt-4">
|
||||||
<span v-html="htmlContent(project.projectDescription)"></span>
|
<span v-html="htmlContent(project.projectDescription)"/>
|
||||||
|
|
||||||
|
|
||||||
<h4>{{ t('project.detail.technologies', 'Verwendete Technologien') }}</h4>
|
<h4>{{ t('project.detail.technologies', 'Verwendete Technologien') }}</h4>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
{{ tech.titel }}
|
{{ tech.titel }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" v-if="project.webpage">
|
<div v-if="project.webpage" class="row">
|
||||||
<div class="col-12 text-end">
|
<div class="col-12 text-end">
|
||||||
<a
|
<a
|
||||||
class="webPageBtn"
|
class="webPageBtn"
|
||||||
@ -93,15 +93,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
name: 'project-link'
|
||||||
|
})
|
||||||
import { ref, computed, watch } from "vue"
|
import { ref, computed, watch } from "vue"
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
const { t } = useI18n()
|
|
||||||
const localePath = useLocalePath()
|
|
||||||
|
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
const route = useRoute()
|
|
||||||
|
|
||||||
import { useMainStore } from '@/stores/main'
|
import { useMainStore } from '@/stores/main'
|
||||||
|
|
||||||
|
import { useHtmlConverter } from '@/composables/useHTMLConverter'
|
||||||
|
const { t } = useI18n()
|
||||||
|
const localePath = useLocalePath()
|
||||||
|
const route = useRoute()
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const project = computed(() => mainStore.getProjectByLink(route.params.link))
|
const project = computed(() => mainStore.getProjectByLink(route.params.link))
|
||||||
const customer = computed(() => {
|
const customer = computed(() => {
|
||||||
@ -121,8 +126,6 @@ watch(project, (newProject) => {
|
|||||||
currentImage.value = null
|
currentImage.value = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { useHtmlConverter } from '@/composables/useHTMLConverter'
|
|
||||||
const { convertToHTML } = useHtmlConverter()
|
const { convertToHTML } = useHtmlConverter()
|
||||||
const htmlContent = (data: string) => {
|
const htmlContent = (data: string) => {
|
||||||
return convertToHTML(data)
|
return convertToHTML(data)
|
||||||
@ -3,18 +3,18 @@
|
|||||||
<section class="topSpace">
|
<section class="topSpace">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{{ $t('pages.references.hero.h1') }}</h1>
|
<h1>{{ $t('pages.references.hero.h1') }}</h1>
|
||||||
<p v-html="$t('pages.references.hero.p')"></p>
|
<p v-html="$t('pages.references.hero.p')"/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="referenceBox" v-if="projects && projects.length">
|
<div v-if="projects && projects.length" class="referenceBox">
|
||||||
<slot>
|
<slot>
|
||||||
<NuxtLink
|
<NuxtLinkLocale
|
||||||
class="reference"
|
|
||||||
v-for="project in projects"
|
v-for="project in projects"
|
||||||
:key="project.id"
|
:key="project.id"
|
||||||
:to="getProjectLink(project.link)"
|
class="reference"
|
||||||
|
:to="localePath({ name: 'project-link', params: { link: project.link } })"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
provider="strapi"
|
provider="strapi"
|
||||||
@ -38,7 +38,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLinkLocale>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<CallToActionBox
|
<CallToActionBox
|
||||||
:headline="$t('pages.references.ctaBox.headline')"
|
:headline="$t('pages.references.ctaBox.headline')"
|
||||||
:text="$t('pages.references.ctaBox.text')"
|
:text="$t('pages.references.ctaBox.text')"
|
||||||
:buttonText="$t('pages.references.ctaBox.button')"
|
:button-text="$t('pages.references.ctaBox.button')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -55,6 +55,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useMainStore } from '@/stores/main'
|
import { useMainStore } from '@/stores/main'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useLocalePath } from '#i18n'
|
||||||
|
const localePath = useLocalePath()
|
||||||
|
|
||||||
const runtimeConfig = useRuntimeConfig();
|
const runtimeConfig = useRuntimeConfig();
|
||||||
const cmsUrl = runtimeConfig.public.cmsBaseUrl
|
const cmsUrl = runtimeConfig.public.cmsBaseUrl
|
||||||
@ -62,8 +64,6 @@ const cmsUrl = runtimeConfig.public.cmsBaseUrl
|
|||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { projects } = storeToRefs(mainStore)
|
const { projects } = storeToRefs(mainStore)
|
||||||
|
|
||||||
import { useI18nPages } from '@/composables/useI18nPages'
|
|
||||||
const { getProjectLink } = useI18nPages()
|
|
||||||
|
|
||||||
function getCustomerLogo(customerId) {
|
function getCustomerLogo(customerId) {
|
||||||
if (!customerId) return ''
|
if (!customerId) return ''
|
||||||
@ -95,7 +95,7 @@ const jsonLdProjects = computed(() => {
|
|||||||
"position": index + 1,
|
"position": index + 1,
|
||||||
"item": {
|
"item": {
|
||||||
"@type": "CreativeWork", // alternativ "WebPage", wenn es sich um Projektseiten handelt
|
"@type": "CreativeWork", // alternativ "WebPage", wenn es sich um Projektseiten handelt
|
||||||
"@id": origin + (project.link ? getProjectLink(project.link) : ''),
|
"@id": origin + (project.link ? project.link : ''),
|
||||||
"name": project.projectTitle || 'Projekt',
|
"name": project.projectTitle || 'Projekt',
|
||||||
"image": cmsUrl + (project.projectImages?.[0]?.url || ''),
|
"image": cmsUrl + (project.projectImages?.[0]?.url || ''),
|
||||||
"description": project.projectDescription?.[0]?.children?.[0]?.text || ''
|
"description": project.projectDescription?.[0]?.children?.[0]?.text || ''
|
||||||
|
|||||||
@ -8,11 +8,89 @@
|
|||||||
headline2: 'pages.services.accessibility.hero.headline2',
|
headline2: 'pages.services.accessibility.hero.headline2',
|
||||||
headline3: 'pages.services.accessibility.hero.headline3'
|
headline3: 'pages.services.accessibility.hero.headline3'
|
||||||
}"
|
}"
|
||||||
|
overlay-image="/uploads/DML_Access_Key_3ccf07fbb4.webp"
|
||||||
|
overlay-alt-text="barrierefreiheit symbol"
|
||||||
|
:overlay-width="'30%'"
|
||||||
|
:overlay-position="{ bottom: '5%', right: '1vw' }"
|
||||||
|
:dark-background="true"
|
||||||
/>
|
/>
|
||||||
|
<section class="targetGroup">
|
||||||
|
|
||||||
|
<div class="container-10">
|
||||||
|
<NuxtImg
|
||||||
|
provider="strapi"
|
||||||
|
src="/uploads/rollstuhl_a67c73b6a9.webp"
|
||||||
|
alt="accessibility"
|
||||||
|
/>
|
||||||
|
<h2>Für wen ist Barrierefreiheit wichtig?</h2>
|
||||||
|
<p>Barrierefreiheit macht Ihre Webseite nicht nur für alle Menschen, insbesondere für Menschen mit Einschränkungen zugänglich, sondern verbessert auch die Auffindbarkeit bei Suchmaschinen und die Nutzbarkeit durch moderne KI-Systeme.</p>
|
||||||
|
<h3>Auf was kommt es bei Barrierefreiheit im Web an?</h3>
|
||||||
|
<ul class="check">
|
||||||
|
<li><b>Tastaturbedienbarkeit:</b> Alle Funktionen sind ohne Maus erreichbar.</li>
|
||||||
|
<li><b>Kontraststarke Gestaltung:</b> Gute Lesbarkeit für alle Sehfähigkeiten.</li>
|
||||||
|
<li><b>Screenreader-Kompatibilität:</b> Inhalte werden klar und verständlich vorgelesen.</li>
|
||||||
|
<li><b>Logische Struktur:</b> Überschriften und Inhalte folgen einer nachvollziehbaren Reihenfolge.</li>
|
||||||
|
<li><b>Barrierefreie Medien:</b> Texte als Alternativen, keine automatisch startenden Videos ohne Kontrolle.</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Möchten Sie wissen, wie barrierefrei Ihre aktuelle Webseite ist?</h3>
|
||||||
|
<button
|
||||||
|
class="pinkBtn" role="button"
|
||||||
|
aria-label="Barrierefreiheitscheck"
|
||||||
|
@click.prevent="toggleContactBubble">Kostenlosen Barrierefreiheits-Check anfordern!</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="legalBasis">
|
||||||
|
<svg class="sectionWave wave-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
<div class="container-10">
|
||||||
|
<h2>Rechtliche Grundlagen für Barrierefreiheit in Deutschland und der EU</h2>
|
||||||
|
<p>Barrierefreiheit im Web ist nicht nur eine gute Praxis, sondern in Deutschland und der Europäischen Union auch gesetzlich vorgeschrieben. Diese Vorgaben sollen sicherstellen, dass digitale Angebote für alle Menschen uneingeschränkt nutzbar sind.</p>
|
||||||
|
|
||||||
|
<h3>Wichtige Gesetze und Verordnungen:</h3>
|
||||||
|
<ul class="check">
|
||||||
|
<li><b>Behindertengleichstellungsgesetz (BGG):</b> Regelt die Barrierefreiheit öffentlicher Einrichtungen und deren digitale Angebote in Deutschland.</li>
|
||||||
|
<li><b>Barrierefreie-Informationstechnik-Verordnung (BITV 2.0):</b> Konkretisiert die Anforderungen des BGG für Webseiten und mobile Anwendungen öffentlicher Stellen.</li>
|
||||||
|
<li><b>EU-Richtlinie 2016/2102:</b> Verpflichtet öffentliche Stellen der Mitgliedstaaten, ihre Websites und mobilen Apps barrierefrei zu gestalten.</li>
|
||||||
|
<li><b>European Accessibility Act (EAA):</b> Richtlinie für barrierefreie Produkte und Dienstleistungen, inklusive digitaler Angebote.</li>
|
||||||
|
<li><b>WCAG 2.1 (Web Content Accessibility Guidelines):</b> International anerkannte technische Standards, die als Basis für gesetzliche Vorgaben dienen.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Die Einhaltung dieser Regelungen schützt Sie vor Abmahnungen und verbessert Ihre Reichweite durch bessere Zugänglichkeit für alle Nutzer.</p>
|
||||||
|
</div>
|
||||||
|
<svg class="sectionWave wave-bottom" style="transform: scale(1,-1)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="implementation">
|
||||||
|
<div class="container-10">
|
||||||
|
<h2>Wie wir Barrierefreiheit für Sie umsetzen</h2>
|
||||||
|
<p>
|
||||||
|
Mit Nuxt im Front-End und Strapi als flexiblem Headless CMS im Back-End, realisieren wir barrierefreie Webseiten, die sowohl technisch sauber als auch leicht wartbar sind.
|
||||||
|
Durch die Trennung von Front-End und Back-End können Inhalte effizient gepflegt und barrierefreie Standards systematisch umgesetzt werden.
|
||||||
|
</p>
|
||||||
|
<h3>Vorteile gegenüber klassischen CMS wie WordPress oder Contao</h3>
|
||||||
|
<ul class="check">
|
||||||
|
<li><b>Modulare Architektur:</b> Flexible Komponenten und wiederverwendbare Module erleichtern die Umsetzung von Barrierefreiheitsstandards.</li>
|
||||||
|
<li><b>Performance:</b> Nuxt generiert schnelle, serverseitig gerenderte Seiten, die für Nutzer und Suchmaschinen gleichermaßen optimal sind.</li>
|
||||||
|
<li><b>SEO & KI-Freundlichkeit:</b> Durch gezielte Meta-Tags und strukturierte Daten unterstützen wir bessere Auffindbarkeit und Kompatibilität mit KI-Systemen.</li>
|
||||||
|
<li><b>Content-Management:</b> Strapi ermöglicht barrierefreie Inhalte mit benutzerfreundlichen Editoren und unterstützt mehrsprachige Seiten einfach.</li>
|
||||||
|
<li><b>Zukunftssicherheit:</b> Moderne Technologien garantieren nachhaltige Wartbarkeit und Erweiterbarkeit der Webseite.</li>
|
||||||
|
</ul>
|
||||||
|
<button v-if="false" class="mintBtn">Mehr zum Thema Headless CMS</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<FAQArea page-link="/leistungen/barrierefreie-webseiten" headline="Weitere Fragen zum Thema Barrierefreiheit im Web" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useMainStore } from '@/stores/main';
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
alias: [
|
alias: [
|
||||||
'/leistungen/barrierefreie-webseiten', // Deutsch
|
'/leistungen/barrierefreie-webseiten', // Deutsch
|
||||||
@ -21,11 +99,27 @@ definePageMeta({
|
|||||||
'/servizi/accessibilita', // Italienisch
|
'/servizi/accessibilita', // Italienisch
|
||||||
'/servicios/accesibilidad', // Spanisch
|
'/servicios/accesibilidad', // Spanisch
|
||||||
'/hizmetler/erisilebilirlik' // Türkisch
|
'/hizmetler/erisilebilirlik' // Türkisch
|
||||||
]
|
],
|
||||||
|
name: 'services-accessibility'
|
||||||
})
|
})
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
const toggleContactBubble = () => mainStore.toggleContactBubble();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
|
.accessiblityPage
|
||||||
|
.legalBasis
|
||||||
|
background: linear-gradient(90deg, #39324A 0%, #403871 100%);
|
||||||
|
color: white
|
||||||
|
padding: 12vh 0
|
||||||
|
margin: 8vh 0
|
||||||
|
.targetGroup
|
||||||
|
img
|
||||||
|
float: left
|
||||||
|
width: 30%
|
||||||
|
max-width: 400px
|
||||||
|
margin: 1rem 2rem 2rem 0
|
||||||
|
.implementation
|
||||||
|
margin: 8vh 0
|
||||||
|
padding: 1vh 0 3vh 0
|
||||||
</style>
|
</style>
|
||||||
173
pages/services/ai/index.vue
Normal file
173
pages/services/ai/index.vue
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<div class="aiPage">
|
||||||
|
<HeroBox
|
||||||
|
image="/uploads/DML_Service_Header_AI_639dd0d7b1.webp"
|
||||||
|
:aria-label="$t('pages.services.ai.hero.ariaLabel')"
|
||||||
|
:content="{
|
||||||
|
headline1: 'pages.services.ai.hero.headline1',
|
||||||
|
headline2: 'pages.services.ai.hero.headline2',
|
||||||
|
headline3: 'pages.services.ai.hero.headline3'
|
||||||
|
}"
|
||||||
|
overlay-image="/uploads/kirby_fly_3de66b2839.webp"
|
||||||
|
overlay-alt-text="ki roboter fliegt"
|
||||||
|
:overlay-width="'32%'"
|
||||||
|
:overlay-position="{ top: '28%', right: '3vw' }"
|
||||||
|
:dark-background="true"
|
||||||
|
/>
|
||||||
|
<section class="whyAI">
|
||||||
|
<div class="container-10">
|
||||||
|
<NuxtImg
|
||||||
|
provider="strapi"
|
||||||
|
src="/uploads/AI_robot_67b96e6a17.webp"
|
||||||
|
alt="roboter sitzt auf mouse"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<h2>{{ $t('pages.services.ai.whyAI.headline') }}</h2>
|
||||||
|
<p>{{ $t('pages.services.ai.whyAI.text1') }}</p>
|
||||||
|
<p>{{ $t('pages.services.ai.whyAI.text2') }}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="targetGroup">
|
||||||
|
<svg class="sectionWave wave-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
<div class="container-10">
|
||||||
|
<h2>{{ $t('pages.services.ai.targetGroup.headline') }}</h2>
|
||||||
|
<ul class="check">
|
||||||
|
<li>
|
||||||
|
<strong>{{ $t('pages.services.ai.targetGroup.point1_headline') }}</strong><br>
|
||||||
|
{{ $t('pages.services.ai.targetGroup.point1_description') }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>{{ $t('pages.services.ai.targetGroup.point2_headline') }}</strong><br>
|
||||||
|
{{ $t('pages.services.ai.targetGroup.point2_description') }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>{{ $t('pages.services.ai.targetGroup.point3_headline') }}</strong><br>
|
||||||
|
{{ $t('pages.services.ai.targetGroup.point3_description') }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>{{ $t('pages.services.ai.targetGroup.point4_headline') }}</strong><br>
|
||||||
|
{{ $t('pages.services.ai.targetGroup.point4_description') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<svg class="sectionWave wave-bottom" style="transform: scale(1,-1)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="howItWorks">
|
||||||
|
<div class="container-10">
|
||||||
|
<h2>{{ $t('pages.services.ai.howItWorks.headline') }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="coderWrap">
|
||||||
|
<div class="text">
|
||||||
|
|
||||||
|
<p>{{ $t('pages.services.ai.howItWorks.pretext') }}</p>
|
||||||
|
<ul class="check">
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point1') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point2') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point3') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point4') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point5') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howItWorks.point6') }}</li>
|
||||||
|
</ul>
|
||||||
|
<p>{{ $t('pages.services.ai.howItWorks.posttext') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="coderArea">
|
||||||
|
<SchemaCoder />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="howWeDo">
|
||||||
|
<svg class="sectionWave wave-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
<div class="container-10">
|
||||||
|
<h2>{{ $t('pages.services.ai.howWeDo.headline') }}</h2>
|
||||||
|
<p>{{ $t('pages.services.ai.howWeDo.text') }}</p>
|
||||||
|
<ul class="check">
|
||||||
|
<li>{{ $t('pages.services.ai.howWeDo.point1') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howWeDo.point2') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howWeDo.point3') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howWeDo.point4') }}</li>
|
||||||
|
<li>{{ $t('pages.services.ai.howWeDo.point5') }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<svg class="sectionWave wave-bottom" style="transform: scale(-1,-1)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20">
|
||||||
|
<path d="M 0 0 L 500 0 L 500 14 Q 354.4 -2.8 250 11 Q 145.6 24.8 0 14 L 0 0 Z" fill="#FFF"/>
|
||||||
|
</svg>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<FAQArea
|
||||||
|
page-link="/leistungen/ki-kompatible-webseiten"
|
||||||
|
:headline="$t('pages.services.ai.faq.headline')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useMainStore } from '@/stores/main'
|
||||||
|
const mainStore = useMainStore()
|
||||||
|
definePageMeta({
|
||||||
|
alias: [
|
||||||
|
'/leistungen/ki-kompatible-webseiten', // Deutsch
|
||||||
|
'/services/ai-compatible-websites', // Englisch
|
||||||
|
'/services/sites-compatibles-ia', // Französisch
|
||||||
|
'/servizi/siti-compatibili-ai', // Italienisch
|
||||||
|
'/servicios/sitios-compatibles-ai', // Spanisch
|
||||||
|
'/hizmetler/ai-uyumlu-websiteler' // Türkisch
|
||||||
|
],
|
||||||
|
name: 'services-ai'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.aiPage
|
||||||
|
.targetGroup
|
||||||
|
background: linear-gradient(90deg, #3A283E 0%, #6A3385 100%);
|
||||||
|
color: white
|
||||||
|
padding: 12vh 0
|
||||||
|
margin: 8vh 0
|
||||||
|
li
|
||||||
|
line-height: 1.5rem
|
||||||
|
margin-bottom: 1.5rem
|
||||||
|
strong
|
||||||
|
font-size: 110%
|
||||||
|
|
||||||
|
.howWeDo
|
||||||
|
background: linear-gradient(90deg, #6A3385 0%, #3A283E 100%);
|
||||||
|
color: white
|
||||||
|
padding: 12vh 0
|
||||||
|
margin: 8vh 0
|
||||||
|
.whyAI
|
||||||
|
padding: 3% 0
|
||||||
|
img
|
||||||
|
width: 30%
|
||||||
|
max-width: 280px
|
||||||
|
float: left
|
||||||
|
margin: 1% 6vw 5% 0
|
||||||
|
.howItWorks
|
||||||
|
overflow: hidden
|
||||||
|
.coderWrap
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: flex-start
|
||||||
|
padding-left: 10%
|
||||||
|
position: relative
|
||||||
|
.text
|
||||||
|
flex: 0 0 auto
|
||||||
|
width: 50%
|
||||||
|
margin-left: 2%
|
||||||
|
|
||||||
|
.coderArea
|
||||||
|
flex: 0 0 auto
|
||||||
|
width: 60%
|
||||||
|
transform: translateX(10%)
|
||||||
|
overflow: hidden
|
||||||
|
</style>
|
||||||
32
pages/services/cms/index.vue
Normal file
32
pages/services/cms/index.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cmsPage">
|
||||||
|
<HeroBox
|
||||||
|
image="/uploads/DML_Service_Header_CMS_a438599970.webp"
|
||||||
|
:aria-label="$t('pages.services.cms.hero.ariaLabel')"
|
||||||
|
:content="{
|
||||||
|
headline1: 'pages.services.cms.hero.headline1',
|
||||||
|
headline2: 'pages.services.cms.hero.headline2',
|
||||||
|
headline3: 'pages.services.cms.hero.headline3'
|
||||||
|
}"
|
||||||
|
:dark-background="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
alias: [
|
||||||
|
'/leistungen/headless-cms', // Deutsch
|
||||||
|
'/services/headless-cms', // Englisch
|
||||||
|
'/services/headless-cms', // Französisch
|
||||||
|
'/servizi/headless-cms', // Italienisch
|
||||||
|
'/servicios/headless-cms', // Spanisch
|
||||||
|
'/hizmetler/headless-cms' // Türkisch
|
||||||
|
],
|
||||||
|
name: 'services-cms'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="servicesPage">
|
||||||
<section class="heroBox_service" aria-labelledby="hero-heading">
|
<section class="heroBox_service" aria-labelledby="hero-heading">
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
provider="strapi"
|
provider="strapi"
|
||||||
@ -102,7 +102,7 @@ class="pinkBtn" role="button"
|
|||||||
|
|
||||||
<MarqueeBanner
|
<MarqueeBanner
|
||||||
:items="projectItems"
|
:items="projectItems"
|
||||||
:logoHeight="200"
|
:logo-height="200"
|
||||||
:title="$t('pages.services.marquee.title')"
|
:title="$t('pages.services.marquee.title')"
|
||||||
link="projekt"
|
link="projekt"
|
||||||
:aria-label="$t('pages.services.marquee.title')"
|
:aria-label="$t('pages.services.marquee.title')"
|
||||||
@ -112,7 +112,7 @@ class="pinkBtn" role="button"
|
|||||||
<CallToActionBox
|
<CallToActionBox
|
||||||
:headline="$t('pages.services.ctaBox.headline')"
|
:headline="$t('pages.services.ctaBox.headline')"
|
||||||
:text="$t('pages.services.ctaBox.text')"
|
:text="$t('pages.services.ctaBox.text')"
|
||||||
:buttonText="$t('pages.services.ctaBox.button')"
|
:button-text="$t('pages.services.ctaBox.button')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -253,179 +253,180 @@ watchEffect(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
.heroBox_service
|
.servicesPage
|
||||||
position: relative
|
.heroBox_service
|
||||||
min-height: 35rem
|
|
||||||
height: 70vh
|
|
||||||
display: flex
|
|
||||||
align-items: center
|
|
||||||
justify-content: center
|
|
||||||
overflow: hidden
|
|
||||||
|
|
||||||
.hero-bg
|
|
||||||
position: absolute
|
|
||||||
inset: 0
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
object-fit: cover
|
|
||||||
object-position: center bottom
|
|
||||||
z-index: 0
|
|
||||||
|
|
||||||
.container-10, h1, h2, h3
|
|
||||||
position: relative
|
position: relative
|
||||||
z-index: 1
|
min-height: 35rem
|
||||||
|
height: 70vh
|
||||||
h1
|
display: flex
|
||||||
margin-top: 3rem
|
align-items: center
|
||||||
z-index: 2
|
|
||||||
color: mix(black, $pink, 2%)
|
|
||||||
font-size: clamp(1rem, .8rem + 1vw, 1.2rem)
|
|
||||||
line-height: 1.5
|
|
||||||
margin-bottom: 0
|
|
||||||
max-width: 70%
|
|
||||||
@media (max-width: $breakPointMD)
|
|
||||||
max-width: 100%
|
|
||||||
h2
|
|
||||||
z-index: 2
|
|
||||||
font-size: clamp(1.4rem, .8rem + 2vw, 2.4rem)
|
|
||||||
line-height: 1.5
|
|
||||||
margin-top: 1rem
|
|
||||||
max-width: 55%
|
|
||||||
font-family: 'Comfortaa'
|
|
||||||
@media (max-width: $breakPointMD)
|
|
||||||
max-width: 90%
|
|
||||||
h3
|
|
||||||
max-width: 55%
|
|
||||||
line-height: 1.5
|
|
||||||
font-size: clamp(1rem, .8rem + 1vw, 1.6rem)
|
|
||||||
@media (max-width: $breakPointMD)
|
|
||||||
max-width: 90%
|
|
||||||
&::after
|
|
||||||
content: ''
|
|
||||||
position: absolute
|
|
||||||
top: 0
|
|
||||||
left: 0
|
|
||||||
width: 50%
|
|
||||||
height: 100%
|
|
||||||
background-image: linear-gradient(to right, rgba(white, .3), transparent)
|
|
||||||
z-index: 1
|
|
||||||
.container
|
|
||||||
z-index: 2
|
|
||||||
|
|
||||||
.webStrategy
|
|
||||||
padding: 4rem 0 3.5rem 0
|
|
||||||
h2
|
|
||||||
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
|
||||||
line-height: 150%
|
|
||||||
font-family: 'Comfortaa'
|
|
||||||
margin-left: 30%
|
|
||||||
h3
|
|
||||||
font-size: clamp(1.1rem, .75rem + 1vw, 1.25rem)
|
|
||||||
line-height: 150%
|
|
||||||
margin-left: 30%
|
|
||||||
p
|
|
||||||
margin-left: 30%
|
|
||||||
button
|
|
||||||
margin-left: 30%
|
|
||||||
&::after
|
|
||||||
content: ''
|
|
||||||
position: absolute
|
|
||||||
top: 5%
|
|
||||||
left: -36vw
|
|
||||||
width: 60vw
|
|
||||||
height: 90%
|
|
||||||
min-height: 550px
|
|
||||||
max-height: 800px
|
|
||||||
background-image: url('https://strapi.digimedialoop.de/uploads/Net_f1020a2216.png')
|
|
||||||
background-repeat: no-repeat
|
|
||||||
background-position: center right
|
|
||||||
background-size: cover
|
|
||||||
border-radius: 42% 49% 52% 48% / 53% 38% 62% 47%
|
|
||||||
animation: bubble-wobble 25s infinite ease alternate, gradient-animation 70s infinite alternate ease-in-out
|
|
||||||
box-shadow: $innerShadow
|
|
||||||
@media(max-width: $breakPointMD)
|
|
||||||
right: -50vw
|
|
||||||
.canDo
|
|
||||||
margin: 12vh 0
|
|
||||||
h2
|
|
||||||
margin-bottom: 3.5rem
|
|
||||||
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
|
||||||
.canDoGrid
|
|
||||||
display: grid
|
|
||||||
gap: 2rem
|
|
||||||
justify-content: center
|
justify-content: center
|
||||||
align-items: stretch
|
overflow: hidden
|
||||||
grid-template-columns: 1fr // Default: 1 Spalte
|
|
||||||
|
|
||||||
@media (min-width: $breakPointMD)
|
.hero-bg
|
||||||
grid-template-columns: repeat(2, 1fr)
|
position: absolute
|
||||||
|
inset: 0
|
||||||
@media (min-width: $breakPointXL)
|
|
||||||
grid-template-columns: repeat(4, 1fr)
|
|
||||||
|
|
||||||
.canDoBox
|
|
||||||
width: 100%
|
width: 100%
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
align-items: center
|
|
||||||
justify-content: flex-start
|
|
||||||
background-image: linear-gradient(to bottom right, transparent , white)
|
|
||||||
box-shadow: 3px 3px 8px 1px $lightgrey
|
|
||||||
border-bottom-right-radius: 1rem
|
|
||||||
padding: 1rem 1.5rem
|
|
||||||
border-right: 1px solid lighten($beige, 0%)
|
|
||||||
border-bottom: 1px solid lighten($beige, 0%)
|
|
||||||
height: 100%
|
height: 100%
|
||||||
|
object-fit: cover
|
||||||
|
object-position: center bottom
|
||||||
|
z-index: 0
|
||||||
|
|
||||||
.canDoItem
|
.container-10, h1, h2, h3
|
||||||
width: 100%
|
position: relative
|
||||||
|
z-index: 1
|
||||||
.imageBox
|
|
||||||
margin: 0rem auto 1rem auto
|
h1
|
||||||
|
margin-top: 3rem
|
||||||
|
z-index: 2
|
||||||
|
color: mix(black, $pink, 2%)
|
||||||
|
font-size: clamp(1rem, .8rem + 1vw, 1.2rem)
|
||||||
|
line-height: 1.5
|
||||||
|
margin-bottom: 0
|
||||||
|
max-width: 70%
|
||||||
|
@media (max-width: $breakPointMD)
|
||||||
|
max-width: 100%
|
||||||
|
h2
|
||||||
|
z-index: 2
|
||||||
|
font-size: clamp(1.4rem, .8rem + 2vw, 2.4rem)
|
||||||
|
line-height: 1.5
|
||||||
|
margin-top: 1rem
|
||||||
|
max-width: 55%
|
||||||
|
font-family: 'Comfortaa'
|
||||||
|
@media (max-width: $breakPointMD)
|
||||||
|
max-width: 90%
|
||||||
|
h3
|
||||||
|
max-width: 55%
|
||||||
|
line-height: 1.5
|
||||||
|
font-size: clamp(1rem, .8rem + 1vw, 1.6rem)
|
||||||
|
@media (max-width: $breakPointMD)
|
||||||
|
max-width: 90%
|
||||||
|
&::after
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
|
width: 50%
|
||||||
|
height: 100%
|
||||||
|
background-image: linear-gradient(to right, rgba(white, .3), transparent)
|
||||||
|
z-index: 1
|
||||||
|
.container
|
||||||
|
z-index: 2
|
||||||
|
|
||||||
|
.webStrategy
|
||||||
|
padding: 4rem 0 3.5rem 0
|
||||||
|
h2
|
||||||
|
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
||||||
|
line-height: 150%
|
||||||
|
font-family: 'Comfortaa'
|
||||||
|
margin-left: 30%
|
||||||
|
h3
|
||||||
|
font-size: clamp(1.1rem, .75rem + 1vw, 1.25rem)
|
||||||
|
line-height: 150%
|
||||||
|
margin-left: 30%
|
||||||
|
p
|
||||||
|
margin-left: 30%
|
||||||
|
button
|
||||||
|
margin-left: 30%
|
||||||
|
&::after
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
top: 5%
|
||||||
|
left: -36vw
|
||||||
|
width: 60vw
|
||||||
|
height: 90%
|
||||||
|
min-height: 550px
|
||||||
|
max-height: 800px
|
||||||
|
background-image: url('https://strapi.digimedialoop.de/uploads/Net_f1020a2216.png')
|
||||||
|
background-repeat: no-repeat
|
||||||
|
background-position: center right
|
||||||
|
background-size: cover
|
||||||
|
border-radius: 42% 49% 52% 48% / 53% 38% 62% 47%
|
||||||
|
animation: bubble-wobble 25s infinite ease alternate, gradient-animation 70s infinite alternate ease-in-out
|
||||||
|
box-shadow: $innerShadow
|
||||||
|
@media(max-width: $breakPointMD)
|
||||||
|
right: -50vw
|
||||||
|
.canDo
|
||||||
|
margin: 12vh 0
|
||||||
|
h2
|
||||||
|
margin-bottom: 3.5rem
|
||||||
|
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
||||||
|
.canDoGrid
|
||||||
|
display: grid
|
||||||
|
gap: 2rem
|
||||||
|
justify-content: center
|
||||||
|
align-items: stretch
|
||||||
|
grid-template-columns: 1fr // Default: 1 Spalte
|
||||||
|
|
||||||
|
@media (min-width: $breakPointMD)
|
||||||
|
grid-template-columns: repeat(2, 1fr)
|
||||||
|
|
||||||
|
@media (min-width: $breakPointXL)
|
||||||
|
grid-template-columns: repeat(4, 1fr)
|
||||||
|
|
||||||
|
.canDoBox
|
||||||
width: 100%
|
width: 100%
|
||||||
max-width: 180px
|
display: flex
|
||||||
aspect-ratio: 5 / 4
|
flex-direction: column
|
||||||
object-fit: cover
|
align-items: center
|
||||||
border-radius: 1rem
|
justify-content: flex-start
|
||||||
display: block
|
background-image: linear-gradient(to bottom right, transparent , white)
|
||||||
|
box-shadow: 3px 3px 8px 1px $lightgrey
|
||||||
&:nth-child(1)
|
border-bottom-right-radius: 1rem
|
||||||
border-radius: $loopShape1
|
padding: 1rem 1.5rem
|
||||||
&:nth-child(2)
|
border-right: 1px solid lighten($beige, 0%)
|
||||||
border-radius: $loopShape2
|
border-bottom: 1px solid lighten($beige, 0%)
|
||||||
&:nth-child(3)
|
height: 100%
|
||||||
border-radius: $loopShape3
|
|
||||||
&:nth-child(4)
|
|
||||||
border-radius: $loopShape4
|
|
||||||
|
|
||||||
h3
|
|
||||||
font-size: 1.2rem
|
|
||||||
line-height: 1.5rem
|
|
||||||
text-align: center
|
|
||||||
font-family: 'Mainfont-Bold'
|
|
||||||
color: darken($pink, 10%)
|
|
||||||
text-transform: uppercase
|
|
||||||
margin-bottom: .5rem
|
|
||||||
|
|
||||||
p
|
|
||||||
font-size: .9rem
|
|
||||||
text-align: left !important
|
|
||||||
|
|
||||||
|
.canDoItem
|
||||||
|
width: 100%
|
||||||
|
|
||||||
.targetGroup
|
.imageBox
|
||||||
background-image: url('https://strapi.digimedialoop.de/uploads/smartphone_Contacts_40ae56a178.jpg')
|
margin: 0rem auto 1rem auto
|
||||||
background-repeat: no-repeat
|
width: 100%
|
||||||
background-size: cover
|
max-width: 180px
|
||||||
background-position: center top
|
aspect-ratio: 5 / 4
|
||||||
min-height: 70vh
|
object-fit: cover
|
||||||
display: flex
|
border-radius: 1rem
|
||||||
align-items: center
|
display: block
|
||||||
justify-content: center
|
|
||||||
position: relative
|
&:nth-child(1)
|
||||||
padding: 3rem 0
|
border-radius: $loopShape1
|
||||||
h2
|
&:nth-child(2)
|
||||||
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
border-radius: $loopShape2
|
||||||
h3
|
&:nth-child(3)
|
||||||
font-size: clamp(1.1rem, .8rem + 1vw, 1.2rem)
|
border-radius: $loopShape3
|
||||||
line-height: 150%
|
&:nth-child(4)
|
||||||
|
border-radius: $loopShape4
|
||||||
|
|
||||||
|
h3
|
||||||
|
font-size: 1.2rem
|
||||||
|
line-height: 1.5rem
|
||||||
|
text-align: center
|
||||||
|
font-family: 'Mainfont-Bold'
|
||||||
|
color: darken($pink, 10%)
|
||||||
|
text-transform: uppercase
|
||||||
|
margin-bottom: .5rem
|
||||||
|
|
||||||
|
p
|
||||||
|
font-size: .9rem
|
||||||
|
text-align: left !important
|
||||||
|
|
||||||
|
|
||||||
|
.targetGroup
|
||||||
|
background-image: url('https://strapi.digimedialoop.de/uploads/smartphone_Contacts_40ae56a178.jpg')
|
||||||
|
background-repeat: no-repeat
|
||||||
|
background-size: cover
|
||||||
|
background-position: center top
|
||||||
|
min-height: 70vh
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
position: relative
|
||||||
|
padding: 3rem 0
|
||||||
|
h2
|
||||||
|
font-size: clamp(1.6rem, 1rem + 2vw, 1.8rem)
|
||||||
|
h3
|
||||||
|
font-size: clamp(1.1rem, .8rem + 1vw, 1.2rem)
|
||||||
|
line-height: 150%
|
||||||
</style>
|
</style>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="accessiblityPage">
|
<div class="seoPage">
|
||||||
<HeroBox
|
<HeroBox
|
||||||
image="/uploads/DML_Service_Header_SEO_b11ae8940a.webp"
|
image="/uploads/DML_Service_Header_SEO_b11ae8940a.webp"
|
||||||
:aria-label="$t('pages.services.seo.hero.ariaLabel')"
|
:aria-label="$t('pages.services.seo.hero.ariaLabel')"
|
||||||
@ -8,6 +8,7 @@
|
|||||||
headline2: 'pages.services.seo.hero.headline2',
|
headline2: 'pages.services.seo.hero.headline2',
|
||||||
headline3: 'pages.services.seo.hero.headline3'
|
headline3: 'pages.services.seo.hero.headline3'
|
||||||
}"
|
}"
|
||||||
|
:dark-background="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -21,7 +22,8 @@ definePageMeta({
|
|||||||
'/servizi/ottimizzazione-motori-di-ricerca',// Italienisch
|
'/servizi/ottimizzazione-motori-di-ricerca',// Italienisch
|
||||||
'/servicios/optimizacion-motores-busqueda', // Spanisch
|
'/servicios/optimizacion-motores-busqueda', // Spanisch
|
||||||
'/hizmetler/arama-motoru-optimizasyonu' // Türkisch
|
'/hizmetler/arama-motoru-optimizasyonu' // Türkisch
|
||||||
]
|
],
|
||||||
|
name: 'services-seo'
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -10,9 +10,9 @@
|
|||||||
<p v-html="$t('pages.webagency.hero.text3')" />
|
<p v-html="$t('pages.webagency.hero.text3')" />
|
||||||
<button
|
<button
|
||||||
class="my-4 pinkBtn"
|
class="my-4 pinkBtn"
|
||||||
@click.prevent="toggleContactBubble"
|
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="Kontaktformular öffnen"
|
aria-label="Kontaktformular öffnen"
|
||||||
|
@click.prevent="toggleContactBubble"
|
||||||
>
|
>
|
||||||
{{ $t('pages.webagency.hero.button') }}
|
{{ $t('pages.webagency.hero.button') }}
|
||||||
</button>
|
</button>
|
||||||
@ -75,9 +75,9 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
class="pinkBtn mt-4"
|
class="pinkBtn mt-4"
|
||||||
@click.prevent="toggleContactBubble"
|
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="Kontaktformular öffnen"
|
aria-label="Kontaktformular öffnen"
|
||||||
|
@click.prevent="toggleContactBubble"
|
||||||
>
|
>
|
||||||
{{ $t('pages.webagency.team.button') }}
|
{{ $t('pages.webagency.team.button') }}
|
||||||
</button>
|
</button>
|
||||||
@ -91,9 +91,9 @@
|
|||||||
<h2>{{ $t('pages.webagency.grafiker.title') }}</h2>
|
<h2>{{ $t('pages.webagency.grafiker.title') }}</h2>
|
||||||
<button
|
<button
|
||||||
class="mintBtn"
|
class="mintBtn"
|
||||||
@click.prevent="navigateTo(designerLink)"
|
|
||||||
role="button"
|
role="button"
|
||||||
aria-label="Zum Angebot für Kreative"
|
aria-label="Zum Angebot für Kreative"
|
||||||
|
@click.prevent="navigateTo(designerLink)"
|
||||||
>
|
>
|
||||||
{{ $t('pages.webagency.grafiker.button') }}
|
{{ $t('pages.webagency.grafiker.button') }}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -111,6 +111,8 @@ export const useMainStore = defineStore('main', {
|
|||||||
contactBoxOpen: false,
|
contactBoxOpen: false,
|
||||||
scrollPosition: 0,
|
scrollPosition: 0,
|
||||||
screenWidth: 1440,
|
screenWidth: 1440,
|
||||||
|
heroBoxHeight: 0,
|
||||||
|
darkHeroBack: false,
|
||||||
companyinfo: null as CompanyInfo | null,
|
companyinfo: null as CompanyInfo | null,
|
||||||
pages: [] as Page[],
|
pages: [] as Page[],
|
||||||
customers: [] as Customer[],
|
customers: [] as Customer[],
|
||||||
@ -162,6 +164,12 @@ export const useMainStore = defineStore('main', {
|
|||||||
setScreenWidth(width: number) {
|
setScreenWidth(width: number) {
|
||||||
this.screenWidth = width
|
this.screenWidth = width
|
||||||
},
|
},
|
||||||
|
setHeroBoxHeight(height: number) {
|
||||||
|
this.heroBoxHeight = height
|
||||||
|
},
|
||||||
|
setDarkHeroBack(value: boolean) {
|
||||||
|
this.darkHeroBack = value
|
||||||
|
},
|
||||||
|
|
||||||
// SEND CONTACT REQUEST TO STRAPI
|
// SEND CONTACT REQUEST TO STRAPI
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user