You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.4 KiB
116 lines
3.4 KiB
<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
|
|
visible: boolean
|
|
badge?: string
|
|
route: string
|
|
}
|
|
|
|
const areas: ProductArea[] = [
|
|
{
|
|
id: 'experimenta',
|
|
label: 'experimenta Jahreskarten',
|
|
icon: Sparkles,
|
|
enabled: true,
|
|
visible: true,
|
|
route: '/experimenta',
|
|
},
|
|
{
|
|
id: 'makerspace',
|
|
label: 'Makerspace Jahreskarten',
|
|
icon: Wrench,
|
|
enabled: true,
|
|
visible: true,
|
|
route: '/products',
|
|
},
|
|
{
|
|
id: 'labs',
|
|
label: 'Labore',
|
|
icon: FlaskConical,
|
|
enabled: false,
|
|
visible: true,
|
|
badge: 'Demnächst',
|
|
route: '/labs',
|
|
},
|
|
]
|
|
|
|
const route = useRoute()
|
|
|
|
const currentArea = computed(() => {
|
|
// Determine current area based on route
|
|
if (route.path.startsWith('/products') || route.path === '/') {
|
|
return 'makerspace-annual-passes'
|
|
} else if (route.path.startsWith('/labs')) {
|
|
return 'labs'
|
|
} else if (route.path.startsWith('/experimenta')) {
|
|
return 'experimenta-annual-passes'
|
|
}
|
|
return 'makerspace-annual-passes'
|
|
})
|
|
|
|
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.filter(area => area.visible)" :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.filter(area => area.visible)" :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>
|
|
|