Browse Source
- Added a new page for displaying experimenta annual passes, integrating ProductCard and ProductGrid components for product presentation. - Updated API to filter products by category, allowing for specific product queries. - Enhanced navigation components, including AreaTabs and RoleSwitcher, to improve user experience and accessibility. - Refactored existing components for better styling consistency and responsiveness. - Improved dropdown menu components with updated styles and hover effects for better usability.main
9 changed files with 207 additions and 64 deletions
@ -0,0 +1,142 @@ |
|||
<script setup lang="ts"> |
|||
/** |
|||
* experimenta Products Listing Page |
|||
* |
|||
* Displays experimenta annual passes using ProductCard and ProductGrid components. |
|||
* Fetches only experimenta category products from the database via API. |
|||
*/ |
|||
|
|||
// Page metadata |
|||
definePageMeta({ |
|||
layout: 'default', |
|||
}) |
|||
|
|||
// Type definition for product |
|||
interface Product { |
|||
id: string |
|||
navProductId: string |
|||
name: string |
|||
description: string |
|||
price: string |
|||
stockQuantity: number |
|||
category: string |
|||
active: boolean |
|||
createdAt: Date |
|||
updatedAt: Date |
|||
} |
|||
|
|||
// Fetch products from API - only experimenta passes |
|||
const { data: products, error, pending } = await useFetch<Product[]>('/api/products', { |
|||
query: { |
|||
category: 'annual-pass', |
|||
}, |
|||
}) |
|||
|
|||
// Map product categories to badges |
|||
const getBadge = (category: string): string | undefined => { |
|||
const badges: Record<string, string> = { |
|||
'annual-pass': 'Beliebt', |
|||
} |
|||
return badges[category] |
|||
} |
|||
|
|||
// Map product categories to discount percentages (for demo) |
|||
const getDiscount = (category: string): number | undefined => { |
|||
const discounts: Record<string, number> = { |
|||
// No discounts for now |
|||
} |
|||
return discounts[category] |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<NuxtLayout name="default"> |
|||
<div class="min-h-screen bg-gradient-primary px-4 py-12 md:px-6 lg:px-8"> |
|||
<!-- Page Header --> |
|||
<div class="mx-auto mb-12 max-w-container-wide text-center"> |
|||
<h1 class="mb-4 text-4xl font-bold text-white md:text-5xl"> |
|||
experimenta Jahreskarten |
|||
</h1> |
|||
<p class="mx-auto max-w-2xl text-lg text-white/80"> |
|||
Erlebe die Ausstellungswelt der experimenta ein ganzes Jahr lang. |
|||
Mit freiem Eintritt zu allen Ausstellungen, Science Dome Shows und Sonderausstellungen. |
|||
</p> |
|||
</div> |
|||
|
|||
<!-- Loading State --> |
|||
<div v-if="pending" class="mx-auto max-w-container-wide text-center"> |
|||
<div class="card-glass inline-block"> |
|||
<p class="text-white/80">Produkte werden geladen...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Error State --> |
|||
<div v-else-if="error" class="mx-auto max-w-container-wide"> |
|||
<div class="card-glass border-red/50 bg-red/10"> |
|||
<h2 class="mb-2 text-xl font-semibold text-red"> |
|||
Fehler beim Laden der Produkte |
|||
</h2> |
|||
<p class="text-white/80"> |
|||
{{ error.message || 'Ein unbekannter Fehler ist aufgetreten.' }} |
|||
</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Products Grid --> |
|||
<div v-else-if="products && products.length > 0" class="mx-auto max-w-container-wide"> |
|||
<ProductGrid :columns="3"> |
|||
<ProductCard |
|||
v-for="product in products" |
|||
:key="product.id" |
|||
image="/img/makerspace-jk-2025.jpg" |
|||
:title="product.name" |
|||
:description="product.description" |
|||
:price="Number(product.price)" |
|||
:badge="getBadge(product.category)" |
|||
:discount-percentage="getDiscount(product.category)" |
|||
:product-id="product.id" |
|||
/> |
|||
</ProductGrid> |
|||
</div> |
|||
|
|||
<!-- Empty State --> |
|||
<div v-else class="mx-auto max-w-container-wide text-center"> |
|||
<div class="card-glass"> |
|||
<h2 class="mb-2 text-xl font-semibold text-white"> |
|||
Keine Produkte verfügbar |
|||
</h2> |
|||
<p class="text-white/80"> |
|||
Aktuell sind keine Produkte verfügbar. Bitte schaue später noch einmal vorbei. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Info Card --> |
|||
<div class="mx-auto mt-12 max-w-container-wide"> |
|||
<div class="card-info card-accent-border"> |
|||
<h2 class="mb-3 text-xl font-semibold text-experimenta-accent"> |
|||
Warum eine experimenta Jahreskarte? |
|||
</h2> |
|||
<ul class="space-y-2 text-white/90"> |
|||
<li class="flex items-start gap-2"> |
|||
<span class="mt-1 text-experimenta-accent">✓</span> |
|||
<span>365 Tage unbegrenzter Zugang zur Ausstellungswelt</span> |
|||
</li> |
|||
<li class="flex items-start gap-2"> |
|||
<span class="mt-1 text-experimenta-accent">✓</span> |
|||
<span>Freier Eintritt zu allen Science Dome Shows</span> |
|||
</li> |
|||
<li class="flex items-start gap-2"> |
|||
<span class="mt-1 text-experimenta-accent">✓</span> |
|||
<span>Zugang zu wechselnden Sonderausstellungen</span> |
|||
</li> |
|||
<li class="flex items-start gap-2"> |
|||
<span class="mt-1 text-experimenta-accent">✓</span> |
|||
<span>Flexible Nutzung – komme so oft du möchtest</span> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</NuxtLayout> |
|||
</template> |
|||
Loading…
Reference in new issue