Add cart button to desktop header with price display

Implemented desktop cart button in navigation header that displays:
- Shopping cart icon with item count badge (red, top-right)
- Total cart price in German locale (EUR)
- Click opens CartSidebar via useCartUI() composable
- Responsive: visible only on lg breakpoint and above
- Hidden on mobile (FAB is used instead)

Uses useCart() composable for itemCount and total, with proper
Intl.NumberFormat formatting for EUR display.

Also standardized CartFAB price formatting to use Intl.NumberFormat
for consistency with rest of codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Bastian Masanek
2025-11-03 11:41:32 +01:00
parent f9a2857abe
commit 9d0e77fc98
2 changed files with 124 additions and 26 deletions

View File

@@ -0,0 +1,75 @@
<script setup lang="ts">
import { ShoppingCart } from 'lucide-vue-next'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
// Get cart data
const { itemCount, total } = useCart()
const { open } = useCartUI()
// Get current route
const route = useRoute()
// Determine if FAB should be visible
const isVisible = computed(() => {
// Only show on /products and /products/[id] routes
const isProductPage = route.path === '/products' || route.path.startsWith('/products/')
// Only show when cart has items
return isProductPage && itemCount.value > 0
})
// Format price as EUR in German locale
const formattedTotal = computed(() => {
return new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
}).format(total.value)
})
// Handle FAB click
function handleClick() {
open()
}
</script>
<template>
<Transition
enter-active-class="transition-all duration-200 ease-out"
enter-from-class="scale-0 opacity-0"
enter-to-class="scale-100 opacity-100"
leave-active-class="transition-all duration-150 ease-in"
leave-from-class="scale-100 opacity-100"
leave-to-class="scale-0 opacity-0"
>
<div v-if="isVisible" class="fixed bottom-20 right-4 z-40">
<!-- FAB Button -->
<Button
@click="handleClick"
class="h-14 w-14 rounded-full shadow-lg transition-all duration-200 hover:scale-110 active:scale-95"
variant="default"
size="icon"
aria-label="Warenkorb öffnen"
>
<!-- Cart icon with relative positioning for badge -->
<div class="relative">
<ShoppingCart class="h-6 w-6" />
<!-- Item count badge -->
<Badge
class="absolute -top-2 -right-2 h-5 min-w-[20px] px-0.5 flex items-center justify-center bg-experimenta-accent text-white text-xs font-bold border border-white dark:border-zinc-950"
>
{{ itemCount > 99 ? '99+' : itemCount }}
</Badge>
</div>
</Button>
<!-- Price text below button -->
<div class="mt-2 text-center">
<p class="text-xs font-semibold text-foreground whitespace-nowrap">
{{ formattedTotal }}
</p>
</div>
</div>
</Transition>
</template>