Refactor Cart UI to Enhance Responsiveness and User Experience
- Replaced CartSheet and CartSidebar components with a new CartResponsive component that adapts to screen size, providing a unified cart experience. - Implemented responsive animations for the cart, allowing it to slide in from the right on desktop and from the bottom on mobile. - Updated styles and layout in tailwind.css to support new animation effects for the cart component.
This commit is contained in:
89
app/components/Cart/CartResponsive.vue
Normal file
89
app/components/Cart/CartResponsive.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<script setup lang="ts">
|
||||
import { useMediaQuery } from '@vueuse/core'
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from '@/components/ui/sheet'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import CartEmpty from './CartEmpty.vue'
|
||||
import CartItem from './CartItem.vue'
|
||||
import CartSummary from './CartSummary.vue'
|
||||
|
||||
// Get cart state and UI controls
|
||||
const { items, itemCount, total, loading, updateItem, removeItem } = useCart()
|
||||
const { isOpen, close } = useCartUI()
|
||||
|
||||
// Detect mobile viewport (< 640px = Tailwind sm breakpoint)
|
||||
const isMobile = useMediaQuery('(max-width: 639px)')
|
||||
|
||||
// Responsive side prop: bottom for mobile, right for desktop
|
||||
const side = computed(() => isMobile.value ? 'bottom' : 'right')
|
||||
|
||||
// Responsive sizing classes
|
||||
const sizeClasses = computed(() =>
|
||||
isMobile.value ? 'h-[90vh]' : 'w-full sm:w-[400px]'
|
||||
)
|
||||
|
||||
// Handle quantity update
|
||||
async function handleUpdateQuantity(itemId: string, quantity: number) {
|
||||
await updateItem(itemId, quantity)
|
||||
}
|
||||
|
||||
// Handle item removal
|
||||
async function handleRemoveItem(itemId: string) {
|
||||
await removeItem(itemId)
|
||||
}
|
||||
|
||||
// Navigate to checkout
|
||||
function handleCheckout() {
|
||||
close()
|
||||
navigateTo('/checkout')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Sheet :open="isOpen" @update:open="(open) => !open && close()">
|
||||
<SheetContent :side="side" :class="[sizeClasses, 'p-0 flex flex-col']">
|
||||
<!-- Header -->
|
||||
<SheetHeader class="px-6 py-4 border-b">
|
||||
<SheetTitle class="text-xl font-bold">
|
||||
Warenkorb ({{ itemCount }})
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div v-if="itemCount === 0" class="flex-1 flex items-start justify-center px-6 pt-8">
|
||||
<CartEmpty />
|
||||
</div>
|
||||
|
||||
<!-- Cart Items + Summary -->
|
||||
<template v-else>
|
||||
<!-- Scrollable Items List -->
|
||||
<ScrollArea class="flex-1 px-6">
|
||||
<div class="space-y-4 py-4">
|
||||
<CartItem
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
:loading="loading"
|
||||
@update:quantity="(qty) => handleUpdateQuantity(item.id, qty)"
|
||||
@remove="handleRemoveItem(item.id)"
|
||||
/>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<!-- Sticky Footer with Summary -->
|
||||
<div class="border-t px-6 py-4 bg-background">
|
||||
<CartSummary
|
||||
:items="items"
|
||||
:total="total"
|
||||
:loading="loading"
|
||||
@checkout="handleCheckout"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</template>
|
||||
Reference in New Issue
Block a user