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.
 
 
 

138 lines
3.9 KiB

<script setup lang="ts">
import { Wrench, FlaskConical, Ticket, Sparkles, GraduationCap, Home } 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: 'start',
label: 'Start',
icon: Home,
enabled: true,
visible: true,
route: '/',
},
{
id: 'makerspace',
label: 'Makerspace Jahreskarte',
icon: Wrench,
enabled: true,
visible: true,
route: '/products',
},
{
id: 'educator',
label: 'Pädagogen Jahreskarte',
icon: GraduationCap,
enabled: false,
visible: true,
badge: 'Demnächst',
route: '/educator',
},
{
id: 'experimenta',
label: 'experimenta Jahreskarte',
icon: Sparkles,
enabled: true,
visible: true,
badge: 'Demnächst',
route: '/experimenta',
},
{
id: 'labs',
label: 'Labore',
icon: FlaskConical,
enabled: false,
visible: false,
badge: 'Demnächst',
route: '/labs',
},
]
const route = useRoute()
const currentArea = computed(() => {
// Determine current area based on route - check areas array dynamically
const currentPath = route.path
// Exact match for root path
if (currentPath === '/') {
return areas.find(area => area.route === '/')?.id || ''
}
// Find area where route path starts with area.route
const matchedArea = areas.find(area =>
area.route !== '/' && currentPath.startsWith(area.route)
)
return matchedArea?.id || ''
})
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.5 bg-white/5">
<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-accent data-[state=active]:text-white data-[state=active]:shadow-md',
!area.enabled && 'opacity-50 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 (matching desktop styling) -->
<div class="md:hidden overflow-x-auto scrollbar-hide">
<div class="inline-flex h-auto items-center justify-center rounded-[35px] bg-white/5 p-1.5 min-w-max">
<button v-for="area in areas.filter(area => area.visible)" :key="area.id" :disabled="!area.enabled" :class="[
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[25px] px-4 py-[10px] text-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-0',
currentArea === area.id
? 'bg-accent text-white shadow-md'
: 'text-white/70 hover:text-white',
!area.enabled && 'opacity-50 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>
</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>