Files
hms-licht-ton/frontend/components/AppHeader.vue
T
A0 Implementation Engineer 3bfa54b4b3 T01: Frontend Foundation – Nuxt 3 + Tailwind + Design Tokens + Layout + Meta
- Nuxt 3 project with @nuxtjs/tailwindcss module
- Tailwind CSS config with A0 Dark Theme design tokens (CSS custom properties)
- AppHeader: sticky, logo, nav, phone, social icons, mobile burger menu
- AppFooter: 4-column grid (Navigation, Kontakt, Rechtliches, Social)
- HmsLogo: SVG with orange #EC6925 border
- error.vue: 404 page with Seite nicht gefunden
- robots.txt server route: Disallow: /
- Meta: noindex, nofollow, noarchive, nosnippet
- JSON-LD: LocalBusiness schema
- OpenGraph tags
- routeRules: SSR/CSR per route
- Shared components: LoadingSkeleton, EmptyState, ErrorState, LegalContentPage, SpeakerIcon
- 42 vitest tests passing
- Build: 0 errors
2026-07-09 01:17:35 +02:00

137 lines
8.9 KiB
Vue

<template>
<header
class="sticky top-0 z-50 bg-panel border-b border-border-default"
role="banner"
>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-14 lg:h-16">
<!-- Logo -->
<NuxtLink to="/" class="flex items-center gap-2 shrink-0" aria-label="HMS Licht & Ton Startseite">
<HmsLogo />
<span class="hidden sm:inline font-bold text-sm tracking-wide text-text">
HMS Licht &amp; Ton
</span>
</NuxtLink>
<!-- Desktop Navigation -->
<nav class="hidden md:flex items-center gap-6" role="navigation" aria-label="Hauptnavigation">
<NuxtLink to="/" class="nav-link">Home</NuxtLink>
<NuxtLink to="/referenzen" class="nav-link">Referenzen</NuxtLink>
<NuxtLink to="/mietkatalog" class="nav-link">Mietkatalog</NuxtLink>
<NuxtLink to="/kontakt" class="nav-link">Kontakt</NuxtLink>
</nav>
<!-- Desktop Right: Phone + Social -->
<div class="hidden md:flex items-center gap-4">
<a
href="tel:+491726264796"
class="flex items-center gap-1.5 text-text-muted hover:text-accent transition-colors duration-fast text-sm font-medium min-h-44px"
aria-label="Telefon anrufen"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 5a2 2 0 012-2h2.5a1 1 0 01.95.68l1.2 3.6a1 1 0 01-.27 1.02L7.5 9.5a12 12 0 005 5l1.2-1.13a1 1 0 011.02-.27l3.6 1.2a1 1 0 01.68.95V19a2 2 0 01-2 2A16 16 0 013 5z"/>
</svg>
<span>+49 172 6264796</span>
</a>
<a
href="https://www.facebook.com/hms.licht.ton"
target="_blank"
rel="noopener noreferrer"
class="text-secondary hover:text-accent transition-colors duration-fast min-h-44px flex items-center"
aria-label="Facebook"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.96.93-1.96 1.89v2.25h3.33l-.53 3.49h-2.8V24C19.61 23.1 24 18.1 24 12.07z"/>
</svg>
</a>
<a
href="https://www.instagram.com/hms.licht.ton"
target="_blank"
rel="noopener noreferrer"
class="text-secondary hover:text-accent transition-colors duration-fast min-h-44px flex items-center"
aria-label="Instagram"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 2.16c3.2 0 3.58.01 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s-.01 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58-.01-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.7 3.7 0 01-1.38-.9 3.7 3.7 0 01-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.17 15.58 2.16 15.2 2.16 12s.01-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.17 8.8 2.16 12 2.16zM12 0C8.74 0 8.33.01 7.05.07 5.78.13 4.9.33 4.14.63a5.9 5.9 0 00-2.13 1.38A5.9 5.9 0 00.63 4.14C.33 4.9.13 5.78.07 7.05.01 8.33 0 8.74 0 12s.01 3.67.07 4.95c.06 1.27.26 2.15.56 2.91a5.9 5.9 0 001.38 2.13 5.9 5.9 0 002.13 1.38c.76.3 1.64.5 2.91.56C8.33 23.99 8.74 24 12 24s3.67-.01 4.95-.07c1.27-.06 2.15-.26 2.91-.56a5.9 5.9 0 002.13-1.38 5.9 5.9 0 001.38-2.13c.3-.76.5-1.64.56-2.91.06-1.28.07-1.69.07-4.95s-.01-3.67-.07-4.95c-.06-1.27-.26-2.15-.56-2.91a5.9 5.9 0 00-1.38-2.13A5.9 5.9 0 0019.86.63c-.76-.3-1.64-.5-2.91-.56C15.67.01 15.26 0 12 0z"/>
<path d="M12 5.84A6.16 6.16 0 1018.16 12 6.16 6.16 0 0012 5.84zm0 10.16A4 4 0 1116 12a4 4 0 01-4 4z"/>
<circle cx="18.41" cy="5.59" r="1.44"/>
</svg>
</a>
</div>
<!-- Mobile Burger Button -->
<button
class="md:hidden flex items-center justify-center w-11 h-11 text-text-muted hover:text-accent transition-colors duration-fast"
:aria-expanded="mobileMenuOpen"
aria-controls="mobile-nav"
aria-label="Menü öffnen/schließen"
@click="toggleMobileMenu"
>
<svg v-if="!mobileMenuOpen" class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
<svg v-else class="w-6 h-6" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 6l12 12M18 6L6 18"/>
</svg>
</button>
</div>
</div>
<!-- Mobile Navigation -->
<nav
v-if="mobileMenuOpen"
id="mobile-nav"
class="md:hidden bg-panel border-t border-border-default"
role="navigation"
aria-label="Mobile Navigation"
>
<div class="px-4 py-3 space-y-1">
<NuxtLink to="/" class="block nav-link px-3 py-3 min-h-44px" @click="closeMobileMenu">Home</NuxtLink>
<NuxtLink to="/referenzen" class="block nav-link px-3 py-3 min-h-44px" @click="closeMobileMenu">Referenzen</NuxtLink>
<NuxtLink to="/mietkatalog" class="block nav-link px-3 py-3 min-h-44px" @click="closeMobileMenu">Mietkatalog</NuxtLink>
<NuxtLink to="/kontakt" class="block nav-link px-3 py-3 min-h-44px" @click="closeMobileMenu">Kontakt</NuxtLink>
<div class="flex items-center gap-4 px-3 pt-4 pb-2 border-t border-border-default mt-2">
<a href="tel:+491726264796" class="flex items-center gap-1.5 text-text-muted hover:text-accent text-sm min-h-44px" @click="closeMobileMenu">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 5a2 2 0 012-2h2.5a1 1 0 01.95.68l1.2 3.6a1 1 0 01-.27 1.02L7.5 9.5a12 12 0 005 5l1.2-1.13a1 1 0 011.02-.27l3.6 1.2a1 1 0 01.68.95V19a2 2 0 01-2 2A16 16 0 013 5z"/>
</svg>
<span>+49 172 6264796</span>
</a>
<a href="https://www.facebook.com/hms.licht.ton" target="_blank" rel="noopener noreferrer" class="text-secondary hover:text-accent min-h-44px flex items-center" aria-label="Facebook" @click="closeMobileMenu">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.96.93-1.96 1.89v2.25h3.33l-.53 3.49h-2.8V24C19.61 23.1 24 18.1 24 12.07z"/>
</svg>
</a>
<a href="https://www.instagram.com/hms.licht.ton" target="_blank" rel="noopener noreferrer" class="text-secondary hover:text-accent min-h-44px flex items-center" aria-label="Instagram" @click="closeMobileMenu">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 2.16c3.2 0 3.58.01 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s-.01 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58-.01-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.7 3.7 0 01-1.38-.9 3.7 3.7 0 01-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.17 15.58 2.16 15.2 2.16 12s.01-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.17 8.8 2.16 12 2.16zM12 0C8.74 0 8.33.01 7.05.07 5.78.13 4.9.33 4.14.63a5.9 5.9 0 00-2.13 1.38A5.9 5.9 0 00.63 4.14C.33 4.9.13 5.78.07 7.05.01 8.33 0 8.74 0 12s.01 3.67.07 4.95c.06 1.27.26 2.15.56 2.91a5.9 5.9 0 001.38 2.13 5.9 5.9 0 002.13 1.38c.76.3 1.64.5 2.91.56C8.33 23.99 8.74 24 12 24s3.67-.01 4.95-.07c1.27-.06 2.15-.26 2.91-.56a5.9 5.9 0 002.13-1.38 5.9 5.9 0 001.38-2.13c.3-.76.5-1.64.56-2.91.06-1.28.07-1.69.07-4.95s-.01-3.67-.07-4.95c-.06-1.27-.26-2.15-.56-2.91a5.9 5.9 0 00-1.38-2.13A5.9 5.9 0 0019.86.63c-.76-.3-1.64-.5-2.91-.56C15.67.01 15.26 0 12 0z"/>
<path d="M12 5.84A6.16 6.16 0 1018.16 12 6.16 6.16 0 0012 5.84zm0 10.16A4 4 0 1116 12a4 4 0 01-4 4z"/>
<circle cx="18.41" cy="5.59" r="1.44"/>
</svg>
</a>
</div>
</div>
</nav>
</header>
</template>
<script setup lang="ts">
const mobileMenuOpen = ref(false);
function toggleMobileMenu(): void {
mobileMenuOpen.value = !mobileMenuOpen.value;
}
function closeMobileMenu(): void {
mobileMenuOpen.value = false;
}
const route = useRoute();
watch(() => route.path, () => {
closeMobileMenu();
});
</script>