Setting the file. One moment. Cart Drawer · Wix Vibe Headless · wix/skills · Skills DocsWix Blog
references/storefront/app/components/CartDrawer.jsx
references/storefront/app/components/CartDrawer.jsx
JavaScript·63 lines·3 KB
7 const lineItems = cart?.lineItems ?? [];
8 if (!isOpen) return null;
9
10 return (
11 <div onClick={() => setIsOpen(false)} className="fixed inset-0 z-50 bg-black/40 flex justify-end">
12 <aside onClick={(e) => e.stopPropagation()}
13 className="w-[min(420px,100%)] h-full flex flex-col bg-background text-foreground border-l border-border font-body">
14 <header className="flex justify-between items-center p-4 border-b border-border">
15 <strong className="font-display">Your cart</strong>
16 <button onClick={() => setIsOpen(false)} aria-label="Close cart"
17 className="border-none bg-transparent cursor-pointer text-xl text-muted-foreground">×</button>
18 </header>
19
20 <div className="flex-1 overflow-y-auto p-4">
21 {lineItems.length === 0 ? (
22 <p className="text-muted-foreground">Your cart is empty.</p>
23 ) : lineItems.map((item) => (
24 <div key={item.id} className="flex gap-3 py-3 px-0 border-b border-border">
25 <img src={item.image?.url} alt={item.productName?.original}
26 className="w-16 h-16 object-cover rounded-sm bg-card" />
27 <div className="flex-1 flex flex-col gap-1">
28 <span className="font-semibold">{item.productName?.original}</span>
29 {item.descriptionLines?.map((dl, i) => (
30 <small key={i} className="text-muted-foreground">
31 {dl.name?.original}: {dl.plainText?.original || dl.colorInfo?.original}
32 </small>
33 ))}
34 <div className="flex items-center gap-2 mt-1">
35 <QtyButton onClick={() => updateQuantity(item.id, Math.max(1, item.quantity - 1))}>−</QtyButton>
36 <span className="min-w-5 text-center">{item.quantity}</span>
37 <QtyButton onClick={() => updateQuantity(item.id, item.quantity + 1)}>+</QtyButton>
38 <button onClick={() => removeItem(item.id)}
39 className="ml-auto border-none bg-transparent cursor-pointer text-muted-foreground text-[13px] underline">Remove</button>
40 </div>
41 </div>
42 <span className="font-semibold">{item.price?.formattedAmount}</span>
43 </div>
44 ))}
45 </div>
46
47 {lineItems.length > 0 && (
48 <footer className="p-4 border-t border-border">
49 <button disabled={loading} onClick={checkout}
50 className={`w-full p-3 bg-primary text-primary-foreground border-none rounded-sm text-[15px] font-semibold ${loading ? "cursor-wait opacity-60" : "cursor-pointer opacity-100"}`}>Checkout</button>
51 </footer>
52 )}
53 </aside>
54 </div>
55 );
56}
57
58function QtyButton({ children, onClick }) {
59 return (
60 <button onClick={onClick}
61 className="w-7 h-7 cursor-pointer leading-none bg-card text-foreground border border-border rounded-sm">{children}</button>
62 );
63}