Enhance navigation and UI components for improved user experience
- Added new AppHeader and BottomNav components for better navigation across the application. - Introduced AreaTabs for product area navigation and integrated RoleSwitcher for user role management. - Created CartButton component to display cart status and item count. - Implemented UserMenu with login/logout functionality and user greeting. - Added Badge component for notifications and status indicators. - Updated layout to accommodate new navigation components and ensure mobile responsiveness. - Created product detail demo page to showcase design patterns and features. - Enhanced existing components with improved styling and functionality.
This commit is contained in:
142
app/components/navigation/RoleSwitcher.vue
Normal file
142
app/components/navigation/RoleSwitcher.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
import { User, GraduationCap, Building2, Check } from 'lucide-vue-next'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import { Button } from '@/components/ui/button'
|
||||
|
||||
// User role types matching our database schema
|
||||
type UserRole = 'individual' | 'educator' | 'company'
|
||||
|
||||
interface RoleOption {
|
||||
value: UserRole
|
||||
label: string
|
||||
description: string
|
||||
icon: any
|
||||
color: string
|
||||
enabled: boolean
|
||||
badge?: string
|
||||
}
|
||||
|
||||
const roles: RoleOption[] = [
|
||||
{
|
||||
value: 'individual',
|
||||
label: 'Privatperson',
|
||||
description: 'für mich',
|
||||
icon: User,
|
||||
color: 'text-purple-600',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
value: 'educator',
|
||||
label: 'Pädagoge',
|
||||
description: 'für Schule/Kita',
|
||||
icon: GraduationCap,
|
||||
color: 'text-orange-500',
|
||||
enabled: false,
|
||||
badge: 'Demnächst',
|
||||
},
|
||||
{
|
||||
value: 'company',
|
||||
label: 'Firma',
|
||||
description: 'für Unternehmen',
|
||||
icon: Building2,
|
||||
color: 'text-blue-600',
|
||||
enabled: false,
|
||||
badge: 'Demnächst',
|
||||
},
|
||||
]
|
||||
|
||||
// Current role - will come from user session later
|
||||
const currentRole = ref<UserRole>('individual')
|
||||
|
||||
const currentRoleData = computed(() => {
|
||||
return roles.find((r) => r.value === currentRole.value) || roles[0]
|
||||
})
|
||||
|
||||
function switchRole(role: UserRole) {
|
||||
if (roles.find((r) => r.value === role)?.enabled) {
|
||||
currentRole.value = role
|
||||
// TODO: Update user session/store with new role
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="gap-2 border-2 border-white/30 bg-white/5 text-white hover:bg-white/10 hover:border-white/50 transition-all duration-200 group"
|
||||
title="Rolle wechseln"
|
||||
>
|
||||
<!-- Context label + role -->
|
||||
<span class="text-xs text-white/70 font-normal hidden md:inline">Du kaufst als:</span>
|
||||
<component :is="currentRoleData.icon" class="h-4 w-4 text-white" />
|
||||
<span class="font-medium text-white">{{ currentRoleData.label }}</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="ml-1 opacity-70 text-white group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9" />
|
||||
</svg>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" class="w-64">
|
||||
<DropdownMenuLabel class="text-sm font-normal text-muted-foreground py-3">
|
||||
Für wen kaufst du?
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem
|
||||
v-for="role in roles"
|
||||
:key="role.value"
|
||||
:disabled="!role.enabled"
|
||||
:class="[
|
||||
'gap-3 py-3 cursor-pointer',
|
||||
!role.enabled && 'opacity-60 cursor-not-allowed',
|
||||
currentRole === role.value && 'bg-purple-50 dark:bg-purple-950',
|
||||
]"
|
||||
@click="switchRole(role.value)"
|
||||
>
|
||||
<component :is="role.icon" :class="['h-5 w-5', role.color]" />
|
||||
|
||||
<div class="flex-1 flex flex-col gap-1">
|
||||
<span class="text-sm font-semibold">{{ role.label }}</span>
|
||||
<span class="text-sm text-muted-foreground">{{ role.description }}</span>
|
||||
</div>
|
||||
|
||||
<Check
|
||||
v-if="currentRole === role.value"
|
||||
class="h-5 w-5 text-green-600 flex-shrink-0"
|
||||
/>
|
||||
|
||||
<Badge v-if="role.badge" variant="secondary" class="text-xs px-2 py-0.5 flex-shrink-0">
|
||||
{{ role.badge }}
|
||||
</Badge>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<div class="px-3 py-2.5 text-sm text-muted-foreground">
|
||||
<p class="leading-relaxed">
|
||||
💡 Weitere Rollen werden in Kürze verfügbar sein.
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
Reference in New Issue
Block a user