Nouveautés
{p.name}
{p.category} • {p.color}
import React, { useState, useMemo } from "react"; import { motion } from "framer-motion"; import { ShoppingCart, Search, X, Filter } from "lucide-react"; // Single-file React component for a small clothing e-commerce site. // Uses TailwindCSS utility classes. Default export is the page component. // Features included: // - Header with search & cart // - Category filters // - Product grid with sample products // - Cart sidebar with add/remove and quantity // - Simple responsive layout, subtle animations with Framer Motion const SAMPLE_PRODUCTS = [ { id: "tshirt-01", name: "T-shirt Essentials", price: 19.99, category: "Tops", img: "https://images.unsplash.com/photo-1520975921755-4b741d9b4e6d?q=80&w=800&auto=format&fit=crop&crop=faces", sizes: ["S", "M", "L", "XL"], color: "Noir", }, { id: "hoodie-01", name: "Hoodie Cozy", price: 49.99, category: "Sweatshirts", img: "https://images.unsplash.com/photo-1602810313697-31114a4f8e30?q=80&w=800&auto=format&fit=crop&crop=faces", sizes: ["S", "M", "L", "XL"], color: "Gris", }, { id: "jacket-01", name: "Veste Légère", price: 79.0, category: "Vêtements d'extérieur", img: "https://images.unsplash.com/photo-1541099649105-f69ad21f3246?q=80&w=800&auto=format&fit=crop&crop=faces", sizes: ["M", "L"], color: "Bleu", }, { id: "pants-01", name: "Pantalon Chino", price: 39.5, category: "Bas", img: "https://images.unsplash.com/photo-1524504388940-b1c1722653e1?q=80&w=800&auto=format&fit=crop&crop=faces", sizes: ["S", "M", "L"], color: "Beige", }, { id: "dress-01", name: "Robe Décontractée", price: 59.99, category: "Robes", img: "https://images.unsplash.com/photo-1503342217505-b0a15ec3261c?q=80&w=800&auto=format&fit=crop&crop=faces", sizes: ["S", "M"], color: "Rouge", }, ]; export default function BoutiqueClothing() { const [query, setQuery] = useState(""); const [activeCategory, setActiveCategory] = useState("Tous"); const [cartOpen, setCartOpen] = useState(false); const [cart, setCart] = useState({}); // { productId: { product, qty, size } } const categories = useMemo(() => { const cats = new Set(SAMPLE_PRODUCTS.map((p) => p.category)); return ["Tous", ...Array.from(cats)]; }, []); const filtered = useMemo(() => { return SAMPLE_PRODUCTS.filter((p) => { if (activeCategory !== "Tous" && p.category !== activeCategory) return false; if (!query) return true; const q = query.toLowerCase(); return ( p.name.toLowerCase().includes(q) || p.category.toLowerCase().includes(q) || (p.color && p.color.toLowerCase().includes(q)) ); }); }, [query, activeCategory]); function addToCart(product, chosenSize = null) { setCart((c) => { const existing = c[product.id]; const qty = existing ? existing.qty + 1 : 1; return { ...c, [product.id]: { product, qty, size: chosenSize || (product.sizes[0] ?? null) }, }; }); setCartOpen(true); } function removeFromCart(productId) { setCart((c) => { const next = { ...c }; delete next[productId]; return next; }); } function changeQty(productId, delta) { setCart((c) => { const item = c[productId]; if (!item) return c; const newQty = Math.max(0, item.qty + delta); if (newQty === 0) { const next = { ...c }; delete next[productId]; return next; } return { ...c, [productId]: { ...item, qty: newQty } }; }); } const cartItems = Object.values(cart); const subtotal = cartItems.reduce((s, it) => s + it.product.price * it.qty, 0); return (
{p.category} • {p.color}