443 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="servicesPage">
<!-- <section class="heroBox_service" aria-labelledby="hero-heading">
<NuxtImg
provider="strapi"
src="/uploads/large_DML_Home_Hero_4f27bc7f8e.webp"
class="hero-bg"
sizes="sm:100vw md:100vw lg:100vw"
alt="website example"
aria-hidden="true"
priority
loading="eager"
preload
fetchpriority="high"
/>
<div class="container-10">
<h1 id="hero-heading">{{ $t('pages.home.heroBox.h1') }}</h1>
<h2>{{ $t('pages.home.heroBox.h2') }}</h2>
<h3>{{ $t('pages.home.heroBox.h3') }}</h3>
</div>
<svg class="sectionWave wave-bottom" style="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20" aria-hidden="true">
<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> -->
<HeroBox
image="/uploads/bubbles_DM_Lmint_trans_08ddb0a921.webp"
:aria-label="$t('pages.services.hero.ariaLabel')"
:dark-background="false"
>
<h1>Webseiten mit Substanz und Strategie</h1>
<h2>Unsere Leistungen verbinden technisches Know-how mit klarer Ausrichtung auf Nutzer, Sichtbarkeit und Zukunftssicherheit</h2>
<h3>Barrierefrei, suchmaschinen-optimiert, mit Headless-Technologie und KI-Kompatibilität passgenau für Ihr digitales Business</h3>
</HeroBox>
<ServicesTeaser />
<!-- <section aria-labelledby="solution-title">
<div class="container-10 webStrategy">
<h2 id="solution-title">{{ $t('pages.home.solution.title') }}</h2>
<h3>{{ $t('pages.home.solution.teaser') }}</h3>
<p>{{ $t('pages.home.solution.text') }}</p>
<button
class="mintBtn"
role="button"
aria-describedby="solution-title"
aria-label="headless CMS Info" @click="navigateToArticle">
{{ $t('pages.home.solution.buttonText') }}
</button>
</div>
</section> -->
<section class="targetGroup" aria-labelledby="invitation-title">
<svg class="sectionWave wave-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20" aria-hidden="true">
<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">
<div class="row">
<div class="col-md-4"/>
<div class="col-md-8 pt-5 pb-5">
<h2 id="invitation-title">{{ $t('pages.home.invitation.title') }}</h2>
<h3>{{ $t('pages.home.invitation.teaser') }}</h3>
<button
class="btn pinkBtn" role="button"
aria-describedby="invitation-title"
aria-label="Kontaktformular öffnen"
@click.prevent="toggleContactBubble">{{ $t('pages.home.invitation.button') }}</button>
</div>
</div>
</div>
<svg class="sectionWave wave-bottom" style="transform: scale(-1,-1)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 20" aria-hidden="true">
<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="canDo" aria-labelledby="canDo-section-title">
<div class="container">
<h2 id="canDo-section-title" class="text-center">
{{ $t('pages.home.canDo.title') }}
</h2>
<div class="canDoGrid">
<div
v-for="(item, index) in canDoItems"
:key="index"
class="canDoBox"
>
<div
class="canDoItem"
:role="index === 2 ? 'group' : null"
:aria-labelledby="index === 2 ? 'cando-title' : null"
>
<NuxtImg
provider="strapi"
:src="item.img"
format="webp"
:modifiers="{ quality: 80 }"
sizes="xs:280px sm:300px md:350px"
class="imageBox"
loading="lazy"
:alt="item.alt"
/>
<h3 :id="index === 2 ? 'cando-title' : null">
{{ $t(item.title) }}
</h3>
<p>{{ $t(item.text) }}</p>
</div>
</div>
</div>
</div>
</section>
<MarqueeBanner
:items="projectItems"
:logo-height="200"
:title="$t('pages.services.marquee.title')"
link="projekt"
:aria-label="$t('pages.services.marquee.title')"
speed="15"
/>
<CallToActionBox
:headline="$t('pages.services.ctaBox.headline')"
:text="$t('pages.services.ctaBox.text')"
:button-text="$t('pages.services.ctaBox.button')"
/>
</div>
</template>
<script setup>
import { storeToRefs } from 'pinia';
import { useMainStore } from '@/stores/main';
import { useI18n } from 'vue-i18n';
import { computed } from 'vue';
const runtimeConfig = useRuntimeConfig()
const origin = runtimeConfig.public.appUrl
const { t } = useI18n();
const mainStore = useMainStore();
const { projects, companyinfo } = storeToRefs(mainStore)
const navigateToArticle = () => {
router.push('/wissenswertes/artikel/design-und-inhalt-sauber-getrennt-warum-headless-webdesign-die-beste-wahl-fuer-moderne-unternehmen-ist');
};
const projectItems = computed(() => {
return projects.value
.filter(project => project.customer && project.projectImages.length > 0)
.map(project => ({
text: project.customer?.company || '',
image: {
url: project.projectImages[0]?.url || '',
alternativeText: project.projectImages[0]?.alternativeText || project.customer?.company || ''
},
link: '/projekt/' + project.link || ''
}))
})
const logoUrl = computed(() => {
if (!companyinfo) return origin + '/logo.svg';
return companyinfo.logo?.data?.attributes?.url
? origin + companyinfo.logo.data.attributes.url
: origin + '/logo.svg';
})
const canDoItems = [
{
img: '/uploads/website_Erfolg_Marketing_3c36a43ba5.png',
alt: 'Website Erfolg Marketing',
title: 'pages.home.canDo.item1.title',
text: 'pages.home.canDo.item1.text',
},
{
img: '/uploads/Kundenbindung_45d45ef3fc.png',
alt: 'Kundenbindung Strategie',
title: 'pages.home.canDo.item2.title',
text: 'pages.home.canDo.item2.text',
},
{
img: '/uploads/Screen_Shot_Tool_20250228133408_beb2a11980.png',
alt: 'Screen Tool Beispiel 1',
title: 'pages.home.canDo.item3.title',
text: 'pages.home.canDo.item3.text',
},
{
img: '/uploads/Screen_Shot_Tool_20250228133812_0a20d4320e.png',
alt: 'Screen Tool Beispiel 2',
title: 'pages.home.canDo.item4.title',
text: 'pages.home.canDo.item4.text',
},
];
// JSON_LD für Services
const jsonLdServices = computed(() => {
if (!companyinfo?.value || !companyinfo.value.company) return null;
return {
"@context": "https://schema.org",
"@type": "ProfessionalService",
"name": companyinfo.value.company,
"url": origin,
"logo": logoUrl.value || (origin + '/logo.svg'),
"description": "Spezialisiert auf JAMstack-Webentwicklung, Headless CMS-Integration und moderne Frontend-Lösungen.",
"address": {
"@type": "PostalAddress",
"streetAddress": companyinfo.value.street || '',
"addressLocality": companyinfo.value.city || '',
"addressRegion": "Bayern",
"postalCode": companyinfo.value.postalcode || '',
"addressCountry": "DE"
},
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Leistungen",
"itemListElement": [
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "JAMstack-Webentwicklung",
"description": "Moderne Webentwicklung mit statischen Seiten und Headless CMS."
}
},
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Headless CMS Integration",
"description": "Flexible CMS-Lösungen für maximale Freiheit im Frontend."
}
},
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Frontend-Entwicklung",
"description": "Moderne Frontend-Frameworks und UI/UX Design."
}
}
]
}
}
})
watchEffect(() => {
if (companyinfo.value && jsonLdServices.value) {
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify(jsonLdServices.value)
}
]
})
}
})
</script>
<style lang="sass">
.servicesPage
.heroBox_service
position: relative
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
z-index: 1
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%
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%
.canDoItem
width: 100%
.imageBox
margin: 0rem auto 1rem auto
width: 100%
max-width: 180px
aspect-ratio: 5 / 4
object-fit: cover
border-radius: 1rem
display: block
&:nth-child(1)
border-radius: $loopShape1
&:nth-child(2)
border-radius: $loopShape2
&:nth-child(3)
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
.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>