Files
gremiumhub/landing/app/app.vue

260 lines
8.4 KiB
Vue

<template>
<UApp>
<!-- Skip link for accessibility -->
<a href="#main-content" class="skip-link"> {{ $t('common.skipToContent') }} </a>
<NuxtRouteAnnouncer />
<!-- Header with transparent background and blur on scroll -->
<UHeader
:title="'GremiumHub'"
:ui="{
root: [
'fixed top-0 left-0 right-0 z-50 transition-all duration-300',
isScrolled
? 'bg-white/90 dark:bg-gray-950/90 backdrop-blur-xl shadow-sm border-b border-gray-200/50 dark:border-gray-800/50'
: 'bg-transparent border-transparent'
].join(' ')
}"
>
<template #title>
<NuxtLink to="/" class="flex items-center gap-2 sm:gap-3 group">
<div
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center shadow-lg shadow-primary-500/25 group-hover:shadow-primary-500/40 transition-shadow"
>
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
</div>
<span
class="hidden sm:inline font-heading text-xl font-bold bg-gradient-to-r from-primary-600 to-cyan-600 bg-clip-text text-transparent"
>
GremiumHub
</span>
</NuxtLink>
</template>
<UNavigationMenu
:items="navigationItems"
:ui="{
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium transition-colors'
}"
/>
<template #right>
<UDropdownMenu
:items="localeMenuItems"
:modal="false"
:ui="{ content: 'min-w-32' }"
:content="{
align: 'end'
}"
>
<UButton
icon="i-lucide-globe"
color="neutral"
variant="ghost"
:aria-label="$t('common.changeLanguage')"
class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400"
/>
</UDropdownMenu>
<UColorModeButton
:ui="{
base: 'text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400'
}"
/>
<UButton
to="#newsletter"
class="hidden sm:flex btn-gradient px-5 py-2.5 rounded-xl font-semibold shadow-lg shadow-primary-500/25 hover:shadow-primary-500/40 transition-shadow"
>
<span>{{ $t('common.stayInformed') }}</span>
</UButton>
</template>
<template #body>
<UNavigationMenu
:items="navigationItems"
orientation="vertical"
class="-mx-2.5"
:ui="{
link: 'text-gray-700 dark:text-gray-200 hover:text-primary-600 dark:hover:text-primary-400 font-medium'
}"
/>
<div class="mt-6 pt-6 border-t border-gray-200 dark:border-gray-800">
<UButton to="#newsletter" size="lg" block class="btn-gradient rounded-xl font-semibold">
{{ $t('common.stayInformed') }}
</UButton>
</div>
</template>
</UHeader>
<!-- Main Content -->
<UMain id="main-content">
<NuxtPage />
</UMain>
<!-- Footer -->
<footer class="bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
<div class="grid grid-cols-1 md:grid-cols-4 gap-8 lg:gap-12">
<!-- Brand column -->
<div class="md:col-span-2">
<NuxtLink to="/" class="flex items-center gap-3 mb-4">
<div
class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-cyan-500 flex items-center justify-center"
>
<UIcon name="i-lucide-scale" class="w-5 h-5 text-white" />
</div>
<span class="font-heading text-xl font-bold text-gray-900 dark:text-white"> GremiumHub </span>
</NuxtLink>
<p class="text-gray-600 dark:text-gray-400 max-w-sm mb-6">
{{ $t('footer.brandDescription') }}
</p>
<div class="flex items-center gap-3">
<UButton
icon="i-lucide-linkedin"
color="neutral"
variant="ghost"
to="https://linkedin.com"
target="_blank"
aria-label="LinkedIn"
class="hover:text-primary-600 dark:hover:text-primary-400"
/>
<UButton
icon="i-lucide-mail"
color="neutral"
variant="ghost"
to="mailto:info@gremiumhub.de"
aria-label="E-Mail"
class="hover:text-primary-600 dark:hover:text-primary-400"
/>
</div>
</div>
<!-- Links column -->
<div>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">{{ $t('common.navigation') }}</h4>
<ul class="space-y-3">
<li v-for="item in navigationItems" :key="item.label">
<NuxtLink
:to="item.to"
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
>
{{ item.label }}
</NuxtLink>
</li>
</ul>
</div>
<!-- Legal column -->
<div>
<h4 class="font-heading font-bold text-gray-900 dark:text-white mb-4">{{ $t('common.legal') }}</h4>
<ul class="space-y-3">
<li v-for="item in footerLinks" :key="item.label">
<NuxtLink
:to="item.to"
class="text-gray-600 dark:text-gray-400 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
>
{{ item.label }}
</NuxtLink>
</li>
</ul>
</div>
</div>
<!-- Bottom bar -->
<div class="mt-12 pt-8 border-t border-gray-200 dark:border-gray-800">
<div class="flex flex-col sm:flex-row justify-between items-center gap-4">
<p class="text-sm text-gray-500 dark:text-gray-400">
© {{ new Date().getFullYear() }} GremiumHub. {{ $t('common.allRightsReserved') }}
</p>
<div class="flex items-center gap-6 text-sm text-gray-500 dark:text-gray-400">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-server" class="w-4 h-4" />
<span>{{ $t('common.hostedInGermany') }}</span>
</div>
<div class="flex items-center gap-2">
<UIcon name="i-lucide-shield-check" class="w-4 h-4" />
<span>{{ $t('common.gdprCompliant') }}</span>
</div>
</div>
</div>
</div>
</div>
</footer>
</UApp>
</template>
<script setup lang="ts">
import type { NavigationMenuItem, DropdownMenuItem } from '@nuxt/ui'
const { t, locale, locales, setLocale } = useI18n()
// Locale dropdown menu items
const localeMenuItems = computed<DropdownMenuItem[]>(() =>
(locales.value as Array<{ code: string; name: string }>).map((l) => ({
label: l.name,
icon: locale.value === l.code ? 'i-lucide-check' : undefined,
active: locale.value === l.code,
onSelect: () => setLocale(l.code as 'en' | 'de')
}))
)
// Track scroll position for header styling
const isScrolled = ref(false)
onMounted(() => {
const handleScroll = () => {
isScrolled.value = window.scrollY > 50
}
window.addEventListener('scroll', handleScroll, { passive: true })
handleScroll() // Check initial position
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
})
})
const navigationItems = computed<NavigationMenuItem[]>(() => [
{
label: t('nav.forWorksCouncils'),
to: '/#betriebsraete',
active: false
},
{
label: t('nav.forCompanies'),
to: '/#unternehmen',
active: false
},
{
label: t('nav.features'),
to: '/#features',
active: false
},
{
label: t('nav.team'),
to: '/team',
active: false
},
{
label: t('nav.contact'),
to: '/#kontakt',
active: false
}
])
const footerLinks = computed<NavigationMenuItem[]>(() => [
{
label: t('footer.imprint'),
to: '/impressum'
},
{
label: t('footer.privacy'),
to: '/datenschutz'
},
{
label: t('footer.terms'),
to: '/agb'
}
])
</script>