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:
131
app/components/navigation/AreaTabs.vue
Normal file
131
app/components/navigation/AreaTabs.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<script setup lang="ts">
|
||||
import { Wrench, FlaskConical, Ticket, Sparkles } from 'lucide-vue-next'
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
|
||||
interface ProductArea {
|
||||
id: string
|
||||
label: string
|
||||
icon: any
|
||||
enabled: boolean
|
||||
badge?: string
|
||||
route: string
|
||||
}
|
||||
|
||||
const areas: ProductArea[] = [
|
||||
{
|
||||
id: 'makerspace',
|
||||
label: 'Makerspace',
|
||||
icon: Wrench,
|
||||
enabled: true,
|
||||
route: '/products',
|
||||
},
|
||||
{
|
||||
id: 'labs',
|
||||
label: 'Labore',
|
||||
icon: FlaskConical,
|
||||
enabled: false,
|
||||
badge: 'Demnächst',
|
||||
route: '/labs',
|
||||
},
|
||||
{
|
||||
id: 'experimenta',
|
||||
label: 'experimenta',
|
||||
icon: Sparkles,
|
||||
enabled: false,
|
||||
badge: 'Demnächst',
|
||||
route: '/experimenta',
|
||||
},
|
||||
]
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const currentArea = computed(() => {
|
||||
// Determine current area based on route
|
||||
if (route.path.startsWith('/products') || route.path === '/') {
|
||||
return 'makerspace'
|
||||
} else if (route.path.startsWith('/labs')) {
|
||||
return 'labs'
|
||||
} else if (route.path.startsWith('/experimenta')) {
|
||||
return 'experimenta'
|
||||
}
|
||||
return 'makerspace'
|
||||
})
|
||||
|
||||
function navigateToArea(area: ProductArea) {
|
||||
if (area.enabled) {
|
||||
navigateTo(area.route)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<!-- Desktop: Tabs -->
|
||||
<Tabs :model-value="currentArea" class="hidden md:block">
|
||||
<TabsList class="h-auto p-1 bg-muted/50">
|
||||
<TabsTrigger
|
||||
v-for="area in areas"
|
||||
:key="area.id"
|
||||
:value="area.id"
|
||||
:disabled="!area.enabled"
|
||||
:class="[
|
||||
'gap-2 data-[state=active]:bg-white dark:data-[state=active]:bg-zinc-900',
|
||||
!area.enabled && 'opacity-60 cursor-not-allowed',
|
||||
]"
|
||||
@click="navigateToArea(area)"
|
||||
>
|
||||
<component :is="area.icon" class="h-4 w-4" />
|
||||
<span>{{ area.label }}</span>
|
||||
<Badge v-if="area.badge" variant="secondary" class="ml-1 text-[10px] px-1.5 py-0">
|
||||
{{ area.badge }}
|
||||
</Badge>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
<!-- Mobile: Horizontal scroll with cards -->
|
||||
<div class="md:hidden overflow-x-auto scrollbar-hide">
|
||||
<div class="flex gap-2 p-1 min-w-max">
|
||||
<button
|
||||
v-for="area in areas"
|
||||
:key="area.id"
|
||||
:disabled="!area.enabled"
|
||||
:class="[
|
||||
'flex items-center gap-2 px-4 py-2 rounded-lg border-2 transition-all whitespace-nowrap',
|
||||
currentArea === area.id
|
||||
? 'bg-purple-600 text-white border-purple-600'
|
||||
: 'bg-white dark:bg-zinc-900 border-border hover:border-purple-300',
|
||||
!area.enabled && 'opacity-60 cursor-not-allowed',
|
||||
]"
|
||||
@click="navigateToArea(area)"
|
||||
>
|
||||
<component
|
||||
:is="area.icon"
|
||||
:class="['h-4 w-4', currentArea === area.id ? 'text-white' : '']"
|
||||
/>
|
||||
<span class="font-medium">{{ area.label }}</span>
|
||||
<Badge
|
||||
v-if="area.badge"
|
||||
:variant="currentArea === area.id ? 'secondary' : 'outline'"
|
||||
class="text-[10px] px-1.5 py-0"
|
||||
>
|
||||
{{ area.badge }}
|
||||
</Badge>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Hide scrollbar but keep functionality */
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user