FIX: some fixes for rollout

Burger
This commit is contained in:
webfussel 2025-05-28 09:49:56 +02:00
parent f7f27838a8
commit 65ebc71431
11 changed files with 268 additions and 119 deletions

64
app/assets/css/burger.css Normal file
View file

@ -0,0 +1,64 @@
.Burger {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
justify-content: flex-end;
align-items: center;
transition: var(--transition-time) ease-in-out;
pointer-events: none;
&.open {
pointer-events: all;
background: rgba(0, 0, 0, 0.5);
& nav {
translate: -15vw 0;
}
}
& nav {
width: clamp(300px, 30vw, 400px);
background: var(--color-black);
align-items: end;
padding: 2rem;
height: max-content;
translate: 110% 0;
transition: 150ms ease-in-out;
border-radius: 20px;
& ul {
display: flex;
flex-direction: column;
gap: 1rem;
font-size: 1.5rem;
& a {
&.active {
color: var(--color-orange);
}
&:hover {
scale: 1.1;
color: var(--color-orange);
}
}
}
}
}
@media (width <= 450px) {
.Burger.open nav {
translate: -10vw 0;
}
}
@media screen and (width >= 1180px) {
.Burger {
display: none;
}
}

View file

@ -61,60 +61,12 @@
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
border-radius: 0; border-radius: 0;
& > label { & > .burger {
all: unset;
display: none; display: none;
width: 30px;
height: 25px;
position: relative; position: relative;
transform: rotate(0deg);
transition: var(--transition-time) ease-in-out; transition: var(--transition-time) ease-in-out;
cursor: pointer; cursor: pointer;
z-index: 20000;
& > span {
display: block;
position: absolute;
height: 5px;
width: 100%;
background: var(--color-white);
border-radius: 9px;
opacity: 1;
left: 0;
transform: rotate(0deg);
transition: .25s ease-in-out;
&:nth-child(1) {
top: 0;
}
&:nth-child(2), &:nth-child(3) {
top: 9px;
}
&:nth-child(4) {
top: 18px;
}
}
}
& > input[type="checkbox"]:checked + label span:nth-child(1) {
top: 18px;
width: 0;
left: 50%;
}
& > input[type="checkbox"]:checked + label span:nth-child(2) {
transform: rotate(45deg);
}
& > input[type="checkbox"]:checked + label span:nth-child(3) {
transform: rotate(-45deg);
}
& > input[type="checkbox"]:checked + label span:nth-child(4) {
top: 18px;
width: 0;
left: 50%;
} }
} }
@ -142,40 +94,14 @@
} }
} }
@media screen and (width < 1180px) { @media screen and (width < 1180px) {
.Header { .Header {
& > .wrapper.wrapper > label { & > .wrapper.wrapper > .burger {
display: block; display: block;
} }
& input[type="checkbox"]:checked ~ nav {
transform: translateX(-15vw);
}
& nav { & nav {
background: var(--color-black); display: none;
position: absolute;
overflow: hidden;
height: 100vh;
width: 100vw;
top: -15px;
transition: var(--transition-time);
transform: translateX(100%);
color: var(--color-white);
flex-direction: column;
& ul {
flex-direction: column;
justify-content: center;
height: 100vh;
gap: 8vh;
& li {
font-size: clamp(1rem, 10vw, 3rem);
}
}
} }
} }
} }

View file

@ -1,5 +1,5 @@
.Person { .Person {
flex-basis: clamp(350px, calc(33% - 3rem), 500px); flex-basis: clamp(200px, calc(33% - 3rem), 500px);
flex-grow: 1; flex-grow: 1;
flex-shrink: 0; flex-shrink: 0;
align-items: center; align-items: center;

26
app/components/Burger.vue Normal file
View file

@ -0,0 +1,26 @@
<template>
<div class="Burger" :class="{ open }">
<nav class="z-4" ref="nav">
<ul>
<li v-for="({label, to, aria, icon}) in navigation" :key="label">
<NuxtLink :to="to" :aria-label="aria" active-class="active" class="inline-flex-row big-gap" @click="close">
<Icon :name="icon" mode="svg" />
{{ label }}
</NuxtLink>
</li>
</ul>
</nav>
</div>
</template>
<script setup lang="ts">
import { navigation } from '../utils/navigation'
const navElement = useTemplateRef('nav')
const nav = useNavigation()
const close = () => nav.hideNavigation()
const open = computed(() => nav.isNavigationVisible.value)
onClickOutside(navElement, close)
</script>

View file

@ -8,15 +8,14 @@
webfussel webfussel
</strong> </strong>
</NuxtLink> </NuxtLink>
<input id="navToggle" v-model="isBurgerOpen" type="checkbox"> <button class="burger" :aria-label="burgerLabel" @click="() => nav.toggleNavigation()">
<label :aria-label="burgerLabel" for="navToggle"> <Icon name="ph:waves" mode="svg" size="2em" />
<span/><span/><span/><span/> </button>
</label>
<nav> <nav>
<ul class="main-nav"> <ul class="main-nav">
<li v-for="({label, to, aria, icon}) in nav" :key="label" @click="isBurgerOpen = false"> <li v-for="({label, to, aria, icon}) in navigation" :key="label">
<NuxtLink :to="to" :aria-label="aria" active-class="active" class="inline-flex-row big-gap"> <NuxtLink :to="to" :aria-label="aria" active-class="active" class="inline-flex-row big-gap">
<Icon :name="`ph:${icon}-duotone`" mode="svg" /> <Icon :name="icon" mode="svg" />
{{ label }} {{ label }}
</NuxtLink> </NuxtLink>
</li> </li>
@ -27,42 +26,17 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { navigation } from '../utils/navigation'
let observer: IntersectionObserver let observer: IntersectionObserver
const header = ref<HTMLElement | null>(null) const header = ref<HTMLElement | null>(null)
const headerWrapper = ref<HTMLElement | null>(null) const headerWrapper = ref<HTMLElement | null>(null)
const stickyWatch = ref<HTMLElement | null>(null) const stickyWatch = ref<HTMLElement | null>(null)
const isBurgerOpen = ref<boolean>(false) const nav = useNavigation()
const burgerOpenLabel = 'Burgermenü öffnen' const burgerOpenLabel = 'Burgermenü öffnen'
const burgerCloseLabel = 'Burgermenü schließen' const burgerCloseLabel = 'Burgermenü schließen'
const burgerLabel = computed(() => isBurgerOpen.value ? burgerCloseLabel : burgerOpenLabel) const burgerLabel = computed(() => nav.isNavigationVisible.value ? burgerCloseLabel : burgerOpenLabel)
const nav = [
{
to: `/booking`,
label: 'Projektbuchung',
icon: 'calendar-check',
aria: 'Link dieser Seite: Preise'
},
{
to: `/flatrate`,
label: 'Flatrate',
icon: 'piggy-bank',
aria: 'Link dieser Seite: Preise'
},
{
to: `/references`,
label: 'Referenzen',
icon: 'sparkle',
aria: 'Link dieser Seite: Referenzen'
},
{
to: `/contact`,
label: 'Kontakt',
icon: 'chats-circle',
aria: 'Link dieser Seite: Kontakt'
},
]
onMounted(() => { onMounted(() => {
observer = new IntersectionObserver(([entry]) => { observer = new IntersectionObserver(([entry]) => {

View file

@ -0,0 +1,24 @@
import { ref } from 'vue'
const isNavigationVisible = ref(false)
export const useNavigation = () => {
const toggleNavigation = () => {
isNavigationVisible.value = !isNavigationVisible.value
}
const showNavigation = () => {
isNavigationVisible.value = true
}
const hideNavigation = () => {
isNavigationVisible.value = false
}
return {
isNavigationVisible,
toggleNavigation,
showNavigation,
hideNavigation
}
}

View file

@ -1,5 +1,6 @@
<template> <template>
<Header /> <Header />
<Burger />
<slot /> <slot />
<Footer /> <Footer />
</template> </template>

26
app/utils/navigation.ts Normal file
View file

@ -0,0 +1,26 @@
export const navigation = [
{
to: `/booking`,
label: 'Projektbuchung',
icon: 'ph:calendar-check-duotone',
aria: 'Link dieser Seite: Preise'
},
{
to: `/flatrate`,
label: 'Flatrate',
icon: 'ph:piggy-bank-duotone',
aria: 'Link dieser Seite: Preise'
},
{
to: `/references`,
label: 'Referenzen',
icon: 'ph:sparkle-duotone',
aria: 'Link dieser Seite: Referenzen'
},
{
to: `/contact`,
label: 'Kontakt',
icon: 'ph:chats-circle-duotone',
aria: 'Link dieser Seite: Kontakt'
},
]

View file

@ -27,6 +27,7 @@ export default defineNuxtConfig({
'~/assets/css/person.css', '~/assets/css/person.css',
'~/assets/css/button.css', '~/assets/css/button.css',
'~/assets/css/spoiler.css', '~/assets/css/spoiler.css',
'~/assets/css/burger.css',
], ],
postcss: { postcss: {
@ -54,9 +55,7 @@ export default defineNuxtConfig({
} }
}, },
modules: [ modules: ['@nuxt/icon', '@vueuse/nuxt'],
'@nuxt/icon'
],
icon: { icon: {
customCollections: [ customCollections: [

109
package-lock.json generated
View file

@ -12,8 +12,10 @@
"@iconify-json/ri": "^1.2.5", "@iconify-json/ri": "^1.2.5",
"@nuxt/fonts": "^0.11.4", "@nuxt/fonts": "^0.11.4",
"@nuxt/icon": "^1.10.3", "@nuxt/icon": "^1.10.3",
"@vueuse/nuxt": "^13.3.0",
"nuxt": "^3.17.4", "nuxt": "^3.17.4",
"postcss-nesting": "^13.0.0" "postcss-nesting": "^13.0.0",
"vue": "^3.5.15"
} }
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
@ -4138,6 +4140,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.21",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
"integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/yauzl": { "node_modules/@types/yauzl": {
"version": "2.10.3", "version": "2.10.3",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
@ -4642,6 +4651,104 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vueuse/core": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.3.0.tgz",
"integrity": "sha512-uYRz5oEfebHCoRhK4moXFM3NSCd5vu2XMLOq/Riz5FdqZMy2RvBtazdtL3gEcmDyqkztDe9ZP/zymObMIbiYSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "13.3.0",
"@vueuse/shared": "13.3.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/@vueuse/metadata": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.3.0.tgz",
"integrity": "sha512-42IzJIOYCKIb0Yjv1JfaKpx8JlCiTmtCWrPxt7Ja6Wzoq0h79+YVXmBV03N966KEmDEESTbp5R/qO3AB5BDnGw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/nuxt": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/nuxt/-/nuxt-13.3.0.tgz",
"integrity": "sha512-7Sw9xZAKqp3NCqwY1LixtkMS0/OH3Y+f8zELlq3Yn9k53ntsvWMKzL2RNKWmhMCAZqaLHBJLBB3q+J+NNrDqXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.17.4",
"@vueuse/core": "13.3.0",
"@vueuse/metadata": "13.3.0",
"local-pkg": "^1.1.1"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"nuxt": "^3.0.0 || ^4.0.0-0",
"vue": "^3.5.0"
}
},
"node_modules/@vueuse/nuxt/node_modules/confbox": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@vueuse/nuxt/node_modules/local-pkg": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz",
"integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"mlly": "^1.7.4",
"pkg-types": "^2.0.1",
"quansync": "^0.2.8"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/nuxt/node_modules/pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
"integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"confbox": "^0.2.1",
"exsolve": "^1.0.1",
"pathe": "^2.0.3"
}
},
"node_modules/@vueuse/shared": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.3.0.tgz",
"integrity": "sha512-L1QKsF0Eg9tiZSFXTgodYnu0Rsa2P0En2LuLrIs/jgrkyiDuJSsPZK+tx+wU0mMsYHUYEjNsuE41uqqkuR8VhA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vue": "^3.5.0"
}
},
"node_modules/@whatwg-node/disposablestack": { "node_modules/@whatwg-node/disposablestack": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz", "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz",

View file

@ -19,7 +19,9 @@
"@iconify-json/ri": "^1.2.5", "@iconify-json/ri": "^1.2.5",
"@nuxt/fonts": "^0.11.4", "@nuxt/fonts": "^0.11.4",
"@nuxt/icon": "^1.10.3", "@nuxt/icon": "^1.10.3",
"@vueuse/nuxt": "^13.3.0",
"nuxt": "^3.17.4", "nuxt": "^3.17.4",
"postcss-nesting": "^13.0.0" "postcss-nesting": "^13.0.0",
"vue": "^3.5.15"
} }
} }