@ -4,13 +4,14 @@ import { Badge } from '@/components/ui/badge'
const route = useRoute ( )
const route = useRoute ( )
const { loggedIn } = useAuth ( )
const { loggedIn } = useAuth ( )
const { itemCount } = useCart ( )
const { open : openCart , isOpen : isCartOpen } = useCartUI ( )
interface NavItem {
interface NavItem {
id : string
id : string
label : string
label : string
icon : any
icon : any
route : string
route : string
badge ? : number
requireAuth ? : boolean
requireAuth ? : boolean
}
}
@ -31,9 +32,8 @@ const navItems: NavItem[] = [
id : 'cart' ,
id : 'cart' ,
label : 'Warenkorb' ,
label : 'Warenkorb' ,
icon : ShoppingCart ,
icon : ShoppingCart ,
route : '/cart' ,
route : '/cart' , / / N o t u s e d f o r n a v i g a t i o n , b u t k e p t f o r c o n s i s t e n c y
badge : 0 , / / T O D O : G e t f r o m c a r t s t o r e
requireAuth : false , / / C a r t s h o u l d b e a c c e s s i b l e w i t h o u t a u t h
requireAuth : true ,
} ,
} ,
{
{
id : 'profile' ,
id : 'profile' ,
@ -43,14 +43,26 @@ const navItems: NavItem[] = [
} ,
} ,
]
]
const isActive = ( itemRoute : string ) => {
const isActive = ( item : NavItem ) => {
if ( itemRoute === '/' ) {
/ / S p e c i a l h a n d l i n g f o r c a r t : c h e c k i f c a r t i s o p e n
if ( item . id === 'cart' ) {
return isCartOpen . value
}
/ / F o r o t h e r i t e m s , c h e c k r o u t e
if ( item . route === '/' ) {
return route . path === '/'
return route . path === '/'
}
}
return route . path . startsWith ( itemRoute )
return route . path . startsWith ( item . r oute)
}
}
function handleNavClick ( item : NavItem ) {
function handleNavClick ( item : NavItem ) {
/ / S p e c i a l h a n d l i n g f o r c a r t : o p e n c a r t i n s t e a d o f n a v i g a t i n g
if ( item . id === 'cart' ) {
openCart ( )
return
}
if ( item . requireAuth && ! loggedIn . value ) {
if ( item . requireAuth && ! loggedIn . value ) {
/ / R e d i r e c t t o a u t h p a g e
/ / R e d i r e c t t o a u t h p a g e
navigateTo ( '/auth' )
navigateTo ( '/auth' )
@ -65,66 +77,46 @@ function handleNavClick(item: NavItem) {
<!-- Mobile Bottom Navigation - only visible on small screens -- >
<!-- Mobile Bottom Navigation - only visible on small screens -- >
< nav
< 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"
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"
role = "navigation" aria - label = "Mobile Navigation" >
aria - label = "Mobile Navigation"
>
< div class = "flex items-center justify-around h-16 px-2" >
< div class = "flex items-center justify-around h-16 px-2" >
< button
< button v -for = " item in navItems " :key ="item.id" : class = " [
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' ,
'flex flex-col items-center justify-center flex-1 gap-1 py-2 px-1 rounded-lg transition-all relative' ,
isActive ( item . route )
isActive ( item )
? 'text-experimenta-accent bg-experimenta-accent/10'
? 'text-experimenta-accent bg-experimenta-accent/10'
: 'text-muted-foreground hover:text-foreground hover:bg-muted' ,
: 'text-muted-foreground hover:text-foreground hover:bg-muted' ,
item . requireAuth && ! loggedIn && 'opacity-75' ,
item . requireAuth && ! loggedIn && 'opacity-75' ,
] "
] " @click=" handleNavClick ( item ) " :aria-label=" item . label " :aria-current=" isActive ( item ) ? 'page' : undefined " >
@ click = "handleNavClick(item)"
: aria - label = "item.label"
: aria - current = "isActive(item.route) ? 'page' : undefined"
>
<!-- Icon with badge -- >
<!-- Icon with badge -- >
< div class = "relative" >
< div class = "relative" >
< component
< component :is ="item.icon" : class = " [
: is = "item.icon"
: class = " [
'h-5 w-5 transition-transform' ,
'h-5 w-5 transition-transform' ,
isActive ( item . route ) && 'scale-110' ,
isActive ( item ) && 'scale-110' ,
] "
] " / >
/ >
<!-- Badge for cart -- >
<!-- Badge for cart -- >
< Badge
< Badge v -if = " item.id = = = ' cart ' & & itemCount > 0 "
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" >
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 } }
>
{ { item . badge > 99 ? '99+' : item . badge } }
< / Badge >
< / Badge >
<!-- Login indicator dot for profile when not logged in -- >
<!-- Login indicator dot for profile when not logged in -- >
< span
< span v -if = " item.id = = = ' profile ' & & ! loggedIn "
v - if = "item.id === 'profile' && !loggedIn"
class = "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-yellow-500 animate-pulse"
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 >
< / div >
<!-- Label -- >
<!-- Label -- >
< span
< span : class = " [
: class = " [
'text-[10px] font-medium transition-all' ,
'text-[10px] font-medium transition-all' ,
isActive ( item . route ) && 'font-bold' ,
isActive ( item ) && 'font-bold' ,
] "
] " >
>
{ { item . label } }
{ { item . label } }
< / span >
< / span >
<!-- Active indicator bar -- >
<!-- Active indicator bar -- >
< span
< span v -if = " isActive ( item ) "
v - if = "isActive(item.route)"
class = "absolute bottom-0 left-1/2 -translate-x-1/2 w-12 h-0.5 bg-experimenta-accent rounded-full"
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 >
< / button >
< / div >
< / div >