Refactor navigation components for improved layout and functionality

- Updated UserMenu.vue to enhance button styling and spacing for a more modern look.
- Simplified CartFAB.vue to always show the cart button when items are present, regardless of the route.
- Adjusted AppHeader.vue for better alignment of elements.
- Enhanced AreaTabs.vue to enable the educator tab and improve badge styling.
- Refined BottomNav.vue to handle cart visibility and navigation more effectively.

These changes aim to enhance user navigation and overall experience within the application.
This commit is contained in:
Bastian Masanek
2025-11-03 19:20:10 +01:00
parent 37a1d234a7
commit a22e4b42ca
10 changed files with 82 additions and 126 deletions

View File

@@ -4,13 +4,14 @@ import { Badge } from '@/components/ui/badge'
const route = useRoute()
const { loggedIn } = useAuth()
const { itemCount } = useCart()
const { open: openCart, isOpen: isCartOpen } = useCartUI()
interface NavItem {
id: string
label: string
icon: any
route: string
badge?: number
requireAuth?: boolean
}
@@ -31,9 +32,8 @@ const navItems: NavItem[] = [
id: 'cart',
label: 'Warenkorb',
icon: ShoppingCart,
route: '/cart',
badge: 0, // TODO: Get from cart store
requireAuth: true,
route: '/cart', // Not used for navigation, but kept for consistency
requireAuth: false, // Cart should be accessible without auth
},
{
id: 'profile',
@@ -43,14 +43,26 @@ const navItems: NavItem[] = [
},
]
const isActive = (itemRoute: string) => {
if (itemRoute === '/') {
const isActive = (item: NavItem) => {
// Special handling for cart: check if cart is open
if (item.id === 'cart') {
return isCartOpen.value
}
// For other items, check route
if (item.route === '/') {
return route.path === '/'
}
return route.path.startsWith(itemRoute)
return route.path.startsWith(item.route)
}
function handleNavClick(item: NavItem) {
// Special handling for cart: open cart instead of navigating
if (item.id === 'cart') {
openCart()
return
}
if (item.requireAuth && !loggedIn.value) {
// Redirect to auth page
navigateTo('/auth')
@@ -65,66 +77,46 @@ function handleNavClick(item: NavItem) {
<!-- Mobile Bottom Navigation - only visible on small screens -->
<nav
class="fixed bottom-0 left-0 right-0 z-50 md:hidden border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 safe-area-inset-bottom"
role="navigation"
aria-label="Mobile Navigation"
>
role="navigation" aria-label="Mobile Navigation">
<div class="flex items-center justify-around h-16 px-2">
<button
v-for="item in navItems"
:key="item.id"
:class="[
'flex flex-col items-center justify-center flex-1 gap-1 py-2 px-1 rounded-lg transition-all relative',
isActive(item.route)
? 'text-experimenta-accent bg-experimenta-accent/10'
: 'text-muted-foreground hover:text-foreground hover:bg-muted',
item.requireAuth && !loggedIn && 'opacity-75',
]"
@click="handleNavClick(item)"
:aria-label="item.label"
:aria-current="isActive(item.route) ? 'page' : undefined"
>
<button v-for="item in navItems" :key="item.id" :class="[
'flex flex-col items-center justify-center flex-1 gap-1 py-2 px-1 rounded-lg transition-all relative',
isActive(item)
? 'text-experimenta-accent bg-experimenta-accent/10'
: 'text-muted-foreground hover:text-foreground hover:bg-muted',
item.requireAuth && !loggedIn && 'opacity-75',
]" @click="handleNavClick(item)" :aria-label="item.label" :aria-current="isActive(item) ? 'page' : undefined">
<!-- Icon with badge -->
<div class="relative">
<component
:is="item.icon"
:class="[
'h-5 w-5 transition-transform',
isActive(item.route) && 'scale-110',
]"
/>
<component :is="item.icon" :class="[
'h-5 w-5 transition-transform',
isActive(item) && 'scale-110',
]" />
<!-- Badge for cart -->
<Badge
v-if="item.badge && item.badge > 0"
class="absolute -top-2 -right-2 h-4 min-w-[16px] px-1 flex items-center justify-center text-[10px] bg-experimenta-accent"
>
{{ item.badge > 99 ? '99+' : item.badge }}
<Badge v-if="item.id === 'cart' && itemCount > 0"
class="absolute -top-2 -right-2 h-4 min-w-[16px] px-1 flex items-center justify-center text-[10px] bg-experimenta-accent">
{{ itemCount > 99 ? '99+' : itemCount }}
</Badge>
<!-- Login indicator dot for profile when not logged in -->
<span
v-if="item.id === 'profile' && !loggedIn"
<span v-if="item.id === 'profile' && !loggedIn"
class="absolute -top-1 -right-1 h-2 w-2 rounded-full bg-yellow-500 animate-pulse"
aria-label="Nicht angemeldet"
/>
aria-label="Nicht angemeldet" />
</div>
<!-- Label -->
<span
:class="[
'text-[10px] font-medium transition-all',
isActive(item.route) && 'font-bold',
]"
>
<span :class="[
'text-[10px] font-medium transition-all',
isActive(item) && 'font-bold',
]">
{{ item.label }}
</span>
<!-- Active indicator bar -->
<span
v-if="isActive(item.route)"
<span v-if="isActive(item)"
class="absolute bottom-0 left-1/2 -translate-x-1/2 w-12 h-0.5 bg-experimenta-accent rounded-full"
aria-hidden="true"
/>
aria-hidden="true" />
</button>
</div>