372 lines
9.1 KiB
Vue
372 lines
9.1 KiB
Vue
<template>
|
|
<nav
|
|
class="mainNav"
|
|
:class="[
|
|
isMenuOpen ? 'active' : '',
|
|
screenWidth < 1350 ? 'mobile-nav' : 'desk-nav',
|
|
scrollPosition > 50 ? 'scrolled' : ''
|
|
]"
|
|
aria-label="Hauptnavigation"
|
|
>
|
|
<!-- Burger Icon als Button -->
|
|
<button
|
|
class="burger"
|
|
@click="toggleMenu"
|
|
v-if="screenWidth < 1350"
|
|
:aria-expanded="isMenuOpen"
|
|
aria-controls="main-navigation"
|
|
:class="{ open: isMenuOpen }"
|
|
type="button"
|
|
>
|
|
<span class="visually-hidden">Menü öffnen</span>
|
|
<span></span>
|
|
<span></span>
|
|
</button>
|
|
|
|
<!-- Navigation -->
|
|
<ul
|
|
:id="'main-navigation'"
|
|
:class="[
|
|
screenWidth < 1350 && isMenuOpen ? 'mobile-menu active' :
|
|
screenWidth < 1350 ? 'mobile-menu' : 'desk-menu'
|
|
]"
|
|
v-show="screenWidth >= 1350 || isMenuOpen"
|
|
>
|
|
<li
|
|
v-for="link in navigationLinks"
|
|
:key="link.label"
|
|
class="nav-item"
|
|
@mouseenter="screenWidth >= 1350 && link.subNav && showSubNav(link.label)"
|
|
@mouseleave="screenWidth >= 1350 && link.subNav && hideSubNav(link.label)"
|
|
>
|
|
<!-- Mit SubNav -->
|
|
<template v-if="link.subNav">
|
|
<button
|
|
v-if="screenWidth < 1350"
|
|
class="subnav-toggle"
|
|
@click="toggleMobileSubNav(link.label)"
|
|
:aria-expanded="isActiveSubNav(link.label)"
|
|
:aria-controls="`submenu-${link.label}`"
|
|
type="button"
|
|
>
|
|
{{ $t(link.label) }}
|
|
<span class="arrow" :class="{ open: isActiveSubNav(link.label) }"></span>
|
|
<span class="visually-hidden">
|
|
{{ isActiveSubNav(link.label) ? 'Untermenü schließen' : 'Untermenü öffnen' }}
|
|
</span>
|
|
</button>
|
|
<div v-else>
|
|
{{ $t(link.label) }}
|
|
<span class="arrow" :class="{ open: isSubNavOpen === link.label }"></span>
|
|
</div>
|
|
|
|
<ul
|
|
:id="`submenu-${link.label}`"
|
|
class="submenu"
|
|
:class="{ open: isActiveSubNav(link.label) }"
|
|
>
|
|
<li v-for="sublink in link.subNav" :key="sublink.label">
|
|
<NuxtLinkLocale
|
|
:to="sublink.routeKey"
|
|
@click.native="handleMobileClose"
|
|
>
|
|
{{ $t(sublink.label) }}
|
|
</NuxtLinkLocale>
|
|
</li>
|
|
</ul>
|
|
</template>
|
|
|
|
<!-- Ohne SubNav -->
|
|
<template v-else>
|
|
<NuxtLinkLocale
|
|
:to="link.routeKey"
|
|
@click.native="handleMobileClose"
|
|
>
|
|
{{ $t(link.label) }}
|
|
</NuxtLinkLocale>
|
|
</template>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue'
|
|
import { useMainStore } from '@/stores/main'
|
|
const mainStore = useMainStore()
|
|
|
|
const screenWidth = computed(() => mainStore.screenWidth)
|
|
const scrollPosition = computed(() => mainStore.scrollPosition)
|
|
|
|
const isSubNavOpen = ref(null)
|
|
const isMobileSubNavOpen = ref(null)
|
|
|
|
function toggleMobileSubNav(routeKey) {
|
|
if (screenWidth.value < 1350) {
|
|
isMobileSubNavOpen.value = isMobileSubNavOpen.value === routeKey ? null : routeKey
|
|
}
|
|
}
|
|
|
|
function showSubNav(routeKey) {
|
|
isSubNavOpen.value = routeKey
|
|
}
|
|
function hideSubNav(routeKey) {
|
|
if (isSubNavOpen.value === routeKey) {
|
|
isSubNavOpen.value = null
|
|
}
|
|
}
|
|
|
|
function isActiveSubNav(label) {
|
|
return (screenWidth.value < 1350 ? isMobileSubNavOpen.value : isSubNavOpen.value) === label
|
|
}
|
|
|
|
const isMenuOpen = computed(() => mainStore.menuOpen)
|
|
const toggleMenu = () => mainStore.toggleMenu()
|
|
|
|
const toggleContactBubble = () => mainStore.toggleContactBubble()
|
|
|
|
const handleMobileClose = () => {
|
|
if (screenWidth.value < 1350 && isMenuOpen.value) {
|
|
toggleMenu()
|
|
} else {
|
|
hideSubNav()
|
|
}
|
|
}
|
|
|
|
const navigationLinks = [
|
|
{
|
|
routeKey: '',
|
|
label: 'menu.webagency',
|
|
subNav: [
|
|
{ routeKey: 'webagency', label: 'menu.menuAbout' },
|
|
{ routeKey: 'magazin', label: 'menu.menuMagazin' }
|
|
]
|
|
},
|
|
{
|
|
routeKey: '',
|
|
label: 'menu.services',
|
|
subNav: [
|
|
{ routeKey: 'services-cms', label: 'menu.menuCms' },
|
|
{ routeKey: 'services-seo', label: 'menu.menuSEO' },
|
|
{ routeKey: 'services-accessibility', label: 'menu.menuAccessibility' },
|
|
{ routeKey: 'services-ai', label: 'menu.menuAi' }
|
|
]
|
|
},
|
|
{
|
|
routeKey: '',
|
|
label: 'menu.sectors',
|
|
subNav: [
|
|
{ routeKey: 'sectors-schools', label: 'menu.menuSchools' },
|
|
{ routeKey: 'sectors-film', label: 'menu.menuFilm' }
|
|
]
|
|
},
|
|
{ routeKey: 'references', label: 'menu.references' }
|
|
]
|
|
</script>
|
|
|
|
<style lang="sass">
|
|
.mainNav
|
|
position: fixed
|
|
z-index: 50
|
|
display: flex
|
|
justify-content: flex-end
|
|
width: auto
|
|
|
|
&.desk-nav
|
|
top: 2rem
|
|
right: 2rem
|
|
background: rgba(white, .9)
|
|
border-radius: 1rem
|
|
transition: .8s
|
|
&.scrolled
|
|
top: -.5rem
|
|
right: -3rem
|
|
background: transparent
|
|
|
|
&.mobile-nav
|
|
top: 0
|
|
right: 0
|
|
background-color: transparent
|
|
|
|
.visually-hidden
|
|
position: absolute
|
|
width: 1px
|
|
height: 1px
|
|
padding: 0
|
|
margin: -1px
|
|
overflow: hidden
|
|
clip: rect(0, 0, 0, 0)
|
|
border: 0
|
|
|
|
.burger
|
|
width: 4rem
|
|
height: 4rem
|
|
border-radius: 50%
|
|
border: 1px solid darken($lightgrey, 35%)
|
|
background-color: $darkgrey
|
|
display: flex
|
|
align-items: center
|
|
justify-content: center
|
|
flex-direction: column
|
|
cursor: pointer
|
|
z-index: 55
|
|
margin: 2rem 1.5rem
|
|
|
|
span
|
|
display: block
|
|
width: 25px
|
|
height: 5px
|
|
background-color: white
|
|
margin: 4px 0
|
|
border-radius: 2rem
|
|
transition: all 0.3s ease
|
|
|
|
&.open
|
|
background-color: transparent
|
|
margin: 1.2rem 1rem
|
|
border: 1px solid transparent
|
|
span
|
|
height: 3px
|
|
&:nth-child(2)
|
|
transform: rotate(45deg) translate(2px, 5px)
|
|
&:nth-child(3)
|
|
transform: rotate(-45deg) translate(3px, -6px)
|
|
|
|
.nav-item
|
|
font-family: 'Comfortaa-Bold'
|
|
text-transform: uppercase
|
|
color: $darkgrey
|
|
font-size: 1.1rem
|
|
cursor: pointer
|
|
a
|
|
text-decoration: none
|
|
color: $darkgrey
|
|
display: inline-block
|
|
transition: .4s
|
|
&:hover
|
|
transform: scale(1.04)
|
|
|
|
.arrow
|
|
display: inline-block
|
|
margin-left: 0.5rem
|
|
transition: transform 0.8s ease
|
|
|
|
&::after
|
|
content: '\276F'
|
|
display: inline-block
|
|
transform: rotate(90deg)
|
|
|
|
&.open::after
|
|
transform: rotate(-90deg)
|
|
|
|
.submenu
|
|
max-height: 0
|
|
opacity: 0
|
|
overflow: hidden
|
|
visibility: hidden
|
|
transition: max-height 0.4s ease-in-out, opacity 0.4s ease-in-out, visibility 0.4s ease-in-out
|
|
&.open
|
|
max-height: 500px
|
|
opacity: 1
|
|
visibility: visible
|
|
|
|
li
|
|
padding: .8rem 1rem .4rem 0
|
|
font-size: 1rem
|
|
line-height: 140%
|
|
position: relative
|
|
&::before
|
|
content: ''
|
|
width: .5rem
|
|
height: .4rem
|
|
background-color: rgba($primaryColor, .9)
|
|
border-radius: $loopShape
|
|
position: absolute
|
|
top: 1.2rem
|
|
left: -1rem
|
|
border-radius: 20px
|
|
|
|
.desk-menu
|
|
list-style: none
|
|
display: flex
|
|
flex-direction: row
|
|
padding: .2rem 3.5rem
|
|
|
|
.nav-item
|
|
position: relative
|
|
padding: 0rem 1rem
|
|
cursor: pointer
|
|
|
|
.submenu
|
|
position: absolute
|
|
top: 100%
|
|
left: -30%
|
|
width: 200%
|
|
background-image: linear-gradient(to bottom, rgba(#fff, 0.1) 0%, rgba(#fff, 0.9) 18%, rgba(#fff, .98) 100%)
|
|
border-bottom-right-radius: 1rem
|
|
border-bottom-left-radius: 1rem
|
|
list-style: none
|
|
padding: 1rem .5rem .5rem 2.5rem
|
|
box-shadow: 1px 4px 4px rgba(0, 0, 0, 0.1)
|
|
z-index: 10
|
|
|
|
|
|
.mobile-menu
|
|
list-style: none
|
|
padding: 5rem 10%
|
|
background-color: rgba($darkgrey, .97)
|
|
width: 6rem
|
|
display: flex
|
|
flex-direction: column
|
|
align-items: flex-start
|
|
transition: .8s
|
|
position: fixed
|
|
top: -1rem
|
|
right: 0
|
|
|
|
&.active
|
|
max-width: 90vw
|
|
width: auto
|
|
max-height: 100vh
|
|
min-height: 70vh
|
|
height: auto
|
|
border-bottom-left-radius: 2rem
|
|
.nav-item
|
|
position: relative
|
|
padding: 1rem 1rem
|
|
cursor: pointer
|
|
font-size: 1.25rem
|
|
color: white
|
|
.subnav-toggle
|
|
background-color: transparent
|
|
border: none
|
|
color: white
|
|
font-size: 1.25rem
|
|
text-transform: uppercase
|
|
margin-top: -6px
|
|
&::before
|
|
content: ''
|
|
width: .7rem
|
|
height: .5rem
|
|
background-color: rgba($primaryColor, .9)
|
|
border-radius: $loopShape
|
|
position: absolute
|
|
top: 1.3rem
|
|
left: -.4rem
|
|
border-radius: 20px
|
|
|
|
.submenu
|
|
margin: 1rem 0 .2rem -1.8rem
|
|
list-style: none
|
|
a
|
|
text-transform: none
|
|
font-size: 1.1rem
|
|
li, a
|
|
transition: .5s
|
|
color: white
|
|
|
|
|
|
</style>
|
|
|