#Panier
46 messages · Page 1 of 1 (latest)
Je vais vous aider à comprendre comment créer un panier simple pour un site e-commerce utilisant les Content Collections d'Astro.
Pour créer un panier simple avec des produits stockés dans une Content Collection, vous devrez:
- Définir votre collection de produits
- Récupérer les données des produits
- Implémenter la fonctionnalité du panier
Voici une approche simple:
1. Définir votre collection de produits
Commencez par créer une Content Collection pour vos produits:
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const products = defineCollection({
loader: glob({ pattern: '**/[^_]*.md', base: "./src/data/products" }),
schema: z.object({
title: z.string(),
price: z.number(),
description: z.string(),
image: z.string().optional(),
// autres propriétés nécessaires
})
});
export const collections = { products };
2. Récupérer les produits
Utilisez getCollection() pour récupérer vos produits:
---
import { getCollection } from 'astro:content';
const products = await getCollection('products');
---
<div class="products">
{products.map(product => (
<div class="product-card">
<h2>{product.data.title}</h2>
<p>{product.data.price}€</p>
<button onclick={`addToCart('${product.id}', '${product.data.title}', ${product.data.price})`}>
Ajouter au panier
</button>
</div>
))}
</div>
3. Implémenter la fonctionnalité du panier
Ajoutez un script client pour gérer le panier avec localStorage:
---
// Votre code Astro...
---
<script>
// Initialiser le panier
let cart = JSON.parse(localStorage.getItem('cart')) || [];
// Fonction pour ajouter au panier
function addToCart(id, title, price) {
const existingItem = cart.find(item => item.id === id);
if (existingItem) {
existingItem.quantity += 1;
} else {
cart.push({ id, title, price, quantity: 1 });
}
// Sauvegarder dans localStorage
localStorage.setItem('cart', JSON.stringify(cart));
updateCartDisplay();
}
// Mettre à jour l'affichage du panier
function updateCartDisplay() {
const cartElement = document.getElementById('cart-items');
const totalElement = document.getElementById('cart-total');
if (cartElement) {
cartElement.innerHTML = '';
let total = 0;
cart.forEach(item => {
const itemTotal = item.price * item.quantity;
total += itemTotal;
const itemElement = document.createElement('div');
itemElement.innerHTML = `
<p>${item.title} x ${item.quantity} - ${itemTotal}€</p>
<button onclick="removeFromCart('${item.id}')">Supprimer</button>
`;
cartElement.appendChild(itemElement);
});
if (totalElement) {
totalElement.textContent = `Total: ${total}€`;
}
}
}
// Fonction pour supprimer du panier
function removeFromCart(id) {
cart = cart.filter(item => item.id !== id);
localStorage.setItem('cart', JSON.stringify(cart));
updateCartDisplay();
}
// Initialiser l'affichage au chargement
document.addEventListener('DOMContentLoaded', updateCartDisplay);
// Exposer les fonctions globalement
window.addToCart = addToCart;
window.removeFromCart = removeFromCart;
</script>
<div id="cart">
<h2>Panier</h2>
<div id="cart-items"></div>
<p id="cart-total">Total: 0€</p>
</div>
Cette solution utilise les Content Collections d'Astro pour gérer vos produits et JavaScript côté client pour implémenter un panier simple avec localStorage. Pour une application e-commerce plus complexe, vous pourriez envisager d'utiliser une solution plus robuste comme une API de panier ou une intégration avec un service de paiement.
Pour récupérer un produit spécifique (par exemple pour une page de détail), vous pouvez utiliser getEntry() comme indiqué dans la documentation d'Astro.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@spiral sparrow L'utilisateur pourra définir une quantité lorsque qu'il accédera à la page produit pour plus de détail. Il pourra aussi modifier la quantité dans le panier aussi. J'aimerai que le panier soit une page. Mais le nombre de produits devra être afficher sur la navbar
Let me check the knowledge base for you again. One moment! :books:
Je vais vous montrer comment implémenter un panier e-commerce avec les fonctionnalités que vous souhaitez dans Astro. Voici une solution qui permet de:
- Définir une quantité sur la page produit
- Modifier la quantité dans le panier
- Avoir une page dédiée pour le panier
- Afficher le nombre de produits dans la navbar
Page produit avec sélection de quantité
---
import Layout from '../layouts/Layout.astro';
import { getEntry } from 'astro:content';
// Récupérer le produit depuis l'ID dans l'URL
const { id } = Astro.params;
const product = await getEntry('products', id);
if (!product) {
return Astro.redirect('/404');
}
---
<Layout title={product.data.title}>
<div class="product-detail">
<img src={product.data.image} alt={product.data.title} />
<h1>{product.data.title}</h1>
<p class="price">{product.data.price}€</p>
<p>{product.data.description}</p>
<div class="add-to-cart">
<label for="quantity">Quantité:</label>
<input type="number" id="quantity" name="quantity" min="1" value="1" />
<button id="add-to-cart-btn">Ajouter au panier</button>
</div>
</div>
<script define:vars={{ product }}>
document.getElementById('add-to-cart-btn').addEventListener('click', () => {
const quantity = parseInt(document.getElementById('quantity').value);
addToCart(product.id, product.data.title, product.data.price, product.data.image, quantity);
});
function addToCart(id, title, price, image, quantity) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
const existingItemIndex = cart.findIndex(item => item.id === id);
if (existingItemIndex >= 0) {
cart[existingItemIndex].quantity += quantity;
} else {
cart.push({ id, title, price, image, quantity });
}
localStorage.setItem('cart', JSON.stringify(cart));
updateCartCount();
// Notification visuelle
alert(`${quantity} ${title} ajouté(s) au panier`);
}
function updateCartCount() {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
const count = cart.reduce((total, item) => total + item.quantity, 0);
// Envoyer un événement personnalisé pour mettre à jour le compteur dans la navbar
window.dispatchEvent(new CustomEvent('cart-updated', { detail: { count } }));
}
</script>
</Layout>
## Navbar avec compteur de produits
```astro
---
// src/components/Navbar.astro
---
<nav>
<div class="logo">
<a href="/">Mon E-commerce</a>
</div>
<div class="nav-links">
<a href="/products">Produits</a>
<a href="/cart" class="cart-link">
Panier <span id="cart-count">0</span>
</a>
</div>
</nav>
<script>
// Mettre à jour le compteur au chargement
function updateCartCount() {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
const count = cart.reduce((total, item) => total + item.quantity, 0);
document.getElementById('cart-count').textContent = count.toString();
}
// Mettre à jour au chargement de la page
document.addEventListener('DOMContentLoaded', updateCartCount);
// Écouter les mises à jour du panier
window.addEventListener('cart-updated', (e) => {
document.getElementById('cart-count').textContent = e.detail.count.toString();
});
// Vérifier périodiquement les changements (utile pour les mises à jour entre onglets)
setInterval(updateCartCount, 2000);
</script>
## Page panier avec modification des quantités
```astro
---
// src/pages/cart.astro
import Layout from '../layouts/Layout.astro';
---
<Layout title="Votre panier">
<h1>Votre panier</h1>
<div id="cart-container">
<div id="cart-items">
<!-- Les éléments du panier seront injectés ici par JavaScript -->
</div>
<div id="cart-summary">
<p>Total: <span id="cart-total">0€</span></p>
<button id="checkout-btn">Passer la commande</button>
</div>
</div>
<div id="empty-cart-message" style="display: none;">
<p>Votre panier est vide.</p>
<a href="/products">Continuer vos achats</a>
</div>
<script>
function renderCart() {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
const cartItemsElement = document.getElementById('cart-items');
const emptyCartMessage = document.getElementById('empty-cart-message');
const cartContainer = document.getElementById('cart-container');
if (cart.length === 0) {
emptyCartMessage.style.display = 'block';
cartContainer.style.display = 'none';
return;
}
emptyCartMessage.style.display = 'none';
cartContainer.style.display = 'block';
// Vider le conteneur
cartItemsElement.innerHTML = '';
// Calculer le total
let total = 0;
// Créer les éléments du panier
cart.forEach((item, index) => {
const itemTotal = item.price * item.quantity;
total += itemTotal;
const itemElement = document.createElement('div');
itemElement.className = 'cart-item';
itemElement.innerHTML = `
<img src="${item.image}" alt="${item.title}" width="80">
<div class="item-details">
<h3>${item.title}</h3>
<p>${item.price}€</p>
</div>
<div class="quantity-controls">
<button class="decrease-btn" data-index="${index}">-</button>
<input type="number" min="1" value="${item.quantity}" class="quantity-input" data-index="${index}">
<button class="increase-btn" data-index="${index}">+</button>
</div>
<p class="item-total">${itemTotal.toFixed(2)}€</p>
<button class="remove-btn" data-index="${index}">Supprimer</button>
`;
cartItemsElement.appendChild(itemElement);
});
// Mettre à jour le total
document.getElementById('cart-total').textContent = `${total.toFixed(2)}€`;
// Ajouter les écouteurs d'événements
setupEventListeners();
// Mettre à jour le compteur dans la navbar
updateCartCount();
}
function setupEventListeners() {
// Boutons d'augmentation de quantité
document.querySelectorAll('.increase-btn').forEach(btn => {
btn.addEventListener('click', () => {
const index = parseInt(btn.dataset.index);
updateQuantity(index, 1);
});
});
// Boutons de diminution de quantité
document.querySelectorAll('.decrease-btn').forEach(btn => {
btn.addEventListener('click', () => {
const index = parseInt(btn.dataset.index);
updateQuantity(index, -1);
});
});
// Champs de saisie de quantité
document.querySelectorAll('.quantity-input').forEach(input => {
input.addEventListener('change', () => {
const index = parseInt(input.dataset.index);
const newQuantity = parseInt(input.value);
if (newQuantity >= 1) {
setQuantity(index, newQuantity);
}
});
});
// Boutons de suppression
document.querySelectorAll('.remove-btn').forEach(btn => {
btn.addEventListener('click', () => {
const index = parseInt(btn.dataset.index);
removeItem(index);
});
});
}
function updateQuantity(index, change) {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
if (cart[index]) {
cart[index].quantity += change;
if (cart[index].quantity < 1) {
cart[index].quantity = 1;
}
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
}
}
function setQuantity(index, quantity) {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
if (cart[index]) {
cart[index].quantity = quantity;
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
}
}
function removeItem(index) {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
if (cart[index]) {
cart.splice(index, 1);
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
}
}
function updateCartCount() {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
const count = cart.reduce((total, item) => total + item.quantity, 0);
// Envoyer un événement personnalisé pour mettre à jour le compteur dans la navbar
window.dispatchEvent(new CustomEvent('cart-updated', { detail: { count } }));
}
// Initialiser le panier au chargement de la page
document.addEventListener('DOMContentLoaded', renderCart);
// Configurer le bouton de commande
document.getElementById('checkout-btn')?.addEventListener('click', () => {
// Rediriger vers la page de paiement ou autre logique
alert('Redirection vers le paiement...');
});
</script>
</Layout>
Pour une solution plus avancée avec sessions côté serveur
Si vous souhaitez une solution plus robuste qui fonctionne même sans JavaScript, vous pourriez utiliser les sessions Astro pour stocker le panier côté serveur. Astro 5.7.0+ prend en charge les sessions nativement, ce qui est idéal pour les paniers d'achat:
---
// src/pages/add-to-cart.astro
export const prerender = false; // Nécessaire pour les sessions
const { id, quantity } = Object.fromEntries(await Astro.request.formData());
const product = await getEntry('products', id);
if (product) {
// Récupérer le panier actuel
const cart = await Astro.session?.get('cart') || [];
// Vérifier si le produit existe déjà
const existingItemIndex = cart.findIndex(item => item.id === id);
if (existingItemIndex >= 0) {
cart[existingItemIndex].quantity += parseInt(quantity);
} else {
cart.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Oui, vous pouvez tout à fait stocker vos produits avec Astro DB et gérer les images produits. Voici comment procéder:
Stocker vos produits avec Astro DB
Astro DB est une solution de base de données SQL entièrement gérée, conçue pour l'écosystème Astro. Pour l'utiliser:
- Installez l'intégration
@astrojs/dbavec la commande:
npx astro add db
- Définissez votre table de produits dans
db/config.ts:
import { defineDb, defineTable, column } from 'astro:db';
const Product = defineTable({
columns: {
id: column.number({ primaryKey: true }),
name: column.text(),
description: column.text(),
price: column.number(),
imagePath: column.text(),
stock: column.number(),
// Ajoutez d'autres colonnes selon vos besoins
}
});
export default defineDb({
tables: { Product },
});
- Vous pourrez ensuite interroger vos produits dans vos composants Astro:
---
import { db } from 'astro:db';
// Récupérer tous les produits
const products = await db.select().from('Product');
// Ou récupérer un produit spécifique
const productId = Astro.params.id;
const product = await db.select().from('Product').where({ id: productId }).get();
---
Gérer les images produits
Pour les images produits, vous avez plusieurs options:
1. Stockage local dans src/
Vous pouvez stocker vos images dans le dossier src/ et utiliser le composant <Image /> d'Astro pour les optimiser:
---
import { Image } from 'astro:assets';
import { db } from 'astro:db';
const products = await db.select().from('Product');
---
{products.map(product => (
<div class="product-card">
<Image
src={import(`../assets/products/${product.imagePath}`)}
alt={product.name}
width={300}
height={300}
/>
<h2>{product.name}</h2>
<p>{product.price}€</p>
</div>
))}
Dans ce cas, vous stockeriez simplement le nom du fichier (ou le chemin relatif) dans la colonne imagePath de votre base de données.
2. Utiliser un DAM (Digital Asset Manager) comme Cloudinary
Pour une solution plus robuste, vous pouvez utiliser un service comme Cloudinary pour héberger vos images:
---
import { CldImage } from 'astro-cloudinary';
import { db } from 'astro:db';
const products = await db.select().from('Product');
---
{products.map(product => (
<div class="product-card">
<CldImage
src={product.imagePath}
width={300}
height={300}
alt={product.name}
/>
<h2>{product.name}</h2>
<p>{product.price}€</p>
</div>
))}
Dans ce cas, vous stockeriez l'identifiant Cloudinary de l'image dans la colonne imagePath de votre base de données.
Pour configurer Cloudinary avec Astro, vous pouvez suivre les instructions dans la documentation officielle de Cloudinary pour Astro.
3. Images dans le dossier public/
Si vous préférez une approche plus simple sans optimisation d'images:
---
import { db } from 'astro:db';
const products = await db.select().from('Product');
---
{products.map(product => (
<div class="product-card">
<img src={`/images/products/${product.imagePath}`} alt={product.name} />
<h2>{product.name}</h2>
<p>{product.price}€</p>
</div>
))}
Dans ce cas, vos images seraient stockées dans public/images/products/ et seraient servies telles quelles, sans optimisation.
Astro DB combiné avec les fonctionnalités de gestion d'images d'Astro vous offre une solution complète pour votre site e-commerce. Vous pouvez ainsi gérer efficacement à la fois vos données produits et vos ressources visuelles.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Oui, il existe des solutions plus simples pour créer un site e-commerce avec Astro sans avoir à tout coder manuellement. Astro s'intègre bien avec plusieurs solutions e-commerce prêtes à l'emploi.
Solutions e-commerce clé en main pour Astro
Snipcart
Snipcart est une plateforme de panier d'achat HTML/JavaScript qui s'intègre facilement à Astro:
<script>
window.SnipcartSettings = {
publicApiKey: "YOUR_API_KEY",
loadStrategy: "on-user-interaction",
};
(function()...); // code fourni par Snipcart
</script>
<button
class="snipcart-add-item"
data-item-id="astro-print"
data-item-price="39.99"
data-item-description="A framed print of the Astro logo."
data-item-image="/assets/images/astro-print.jpg"
data-item-name="Astro Print">
Ajouter au panier
</button>
Il existe même un template Astro-Snipcart prêt à l'emploi: astro-snipcart qui offre une solution complète avec système de design optionnel Link title.
Lemon Squeezy
Pour une solution encore plus simple, Lemon Squeezy permet d'ajouter un bouton d'achat avec un overlay de paiement:
<script src="<https://app.lemonsqueezy.com/js/lemon.js"> defer></script>
<a class="lemonsqueezy-button" href="<https://demo.lemonsqueezy.com/checkout/...">>
Acheter maintenant
</a>
Autres solutions
Astro est compatible avec de nombreuses solutions e-commerce comme indiqué dans la documentation officielle:
- Paddle
- Stripe
- Et d'autres services de paiement qui s'intègrent via JavaScript
Ressources communautaires
La communauté Astro propose également des ressources pour l'e-commerce:
Ces solutions vous permettent de mettre en place rapidement un site e-commerce fonctionnel sans avoir à coder toutes les fonctionnalités vous-même, tout en profitant des avantages d'Astro comme la rapidité et l'optimisation du contenu.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@spiral sparrow Je viens de faire un cntent collection de produits en json voici mon shema :
Let me check the knowledge base for you again. One moment! :books:
Je vois que vous avez commencé à créer une collection de produits en JSON pour votre site e-commerce Astro, mais vous n'avez pas partagé votre schéma dans votre message.
Pour vous aider efficacement, j'aurais besoin de voir le schéma que vous avez créé. Pourriez-vous partager le code de votre fichier content.config.ts ou content.config.js où vous avez défini votre collection de produits?
Un schéma typique pour une collection de produits e-commerce pourrait ressembler à ceci:
import { defineCollection, z } from 'astro:content';
import { file } from 'astro/loaders';
const products = defineCollection({
loader: file("src/data/products.json"),
schema: z.object({
id: z.string(),
name: z.string(),
price: z.number(),
description: z.string(),
image: z.string().optional(),
category: z.string().optional(),
inStock: z.boolean().default(true),
// autres propriétés selon vos besoins
})
});
export const collections = { products };
N'hésitez pas à partager votre schéma pour que je puisse vous donner des conseils plus précis sur sa structure et son utilisation dans votre projet e-commerce Astro.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@spiral sparrow Je viens de faire un cntent collection de produits en json voici mon shema :
schema: z.object({
image: z.string().url(),
name: z.string(),
description: z.string(),
price: z.number(),
category: z.enum(['Électronique', 'Mode', 'Maison & Jardin', 'Beauté & Santé', 'Sport', 'Jeux & Jouets', 'Alimentation & Boissons']),
status: z.enum(['En stock', 'Indisponible', 'Disponible fournisseur']),
variations: z.array(
z.object({ title: z.string(), value: z.array(z.string()) })
).optional(),
}),
Comment afficher la variation ?
Let me check the knowledge base for you again. One moment! :books:
Je vois que vous avez créé un schéma pour votre collection de produits avec des variations. Voici comment vous pourriez afficher ces variations dans votre site e-commerce Astro.
Pour afficher les variations d'un produit, vous devrez d'abord récupérer le produit depuis votre collection, puis créer une interface utilisateur permettant de sélectionner les différentes options.
Voici un exemple de composant Astro qui affiche un produit avec ses variations :
---
import { getEntry } from 'astro:content';
// Récupérer le produit (exemple avec un ID passé en paramètre)
const { id } = Astro.params;
const product = await getEntry('products', id);
if (!product) {
return Astro.redirect('/404');
}
---
<div class="product-detail">
<img src={product.data.image} alt={product.data.name} />
<h1>{product.data.name}</h1>
<p class="price">{product.data.price}€</p>
<p class="status">{product.data.status}</p>
<p class="description">{product.data.description}</p>
{product.data.variations && (
<div class="variations">
{product.data.variations.map((variation) => (
<div class="variation-group">
<h3>{variation.title}</h3>
<div class="variation-options">
{variation.value.map((option) => (
<label class="option">
<input
type="radio"
name={variation.title}
value={option}
class="variation-input"
/>
<span class="option-label">{option}</span>
</label>
))}
</div>
</div>
))}
</div>
)}
<button id="add-to-cart-btn">Ajouter au panier</button>
</div>
<script define:vars={{ product }}>
// Récupérer les variations sélectionnées lors de l'ajout au panier
document.getElementById('add-to-cart-btn').addEventListener('click', () => {
const selectedVariations = {};
// Si le produit a des variations, les récupérer
if (product.data.variations) {
product.data.variations.forEach(variation => {
const selected = document.querySelector(`input[name="${variation.title}"]:checked`);
if (selected) {
selectedVariations[variation.title] = selected.value;
}
});
}
// Ajouter au panier avec les variations sélectionnées
addToCart(
product.id,
product.data.name,
product.data.price,
product.data.image,
1, // quantité par défaut
selectedVariations
);
});
function addToCart(id, name, price, image, quantity, variations) {
let cart = JSON.parse(localStorage.getItem('cart')) || [];
// Créer une clé unique pour ce produit avec ses variations spécifiques
const variationKey = Object.entries(variations).map(([key, value]) => `${key}:${value}`).join('|');
const productKey = variationKey ? `${id}-${variationKey}` : id;
const existingItemIndex = cart.findIndex(item => item.productKey === productKey);
if (existingItemIndex >= 0) {
cart[existingItemIndex].quantity += quantity;
} else {
cart.push({
id,
productKey,
name,
price,
image,
quantity,
variations
});
}
localStorage.setItem('cart', JSON.stringify(cart));
// Notification
alert(`Produit ajouté au panier avec les options: ${Object.entries(variations).map(([key, value]) => `${key}: ${value}`).join(', ')}`);
}
</script>
Dans le panier, vous devrez également afficher les variations sélectionnées pour chaque produit :
---
// src/pages/cart.astro
import Layout from '../layouts/Layout.astro';
---
<Layout title="Votre panier">
<h1>Votre panier</h1>
<div id="cart-items">
<!-- Les éléments du panier seront injectés ici -->
</div>
<script>
function renderCart() {
const cart = JSON.parse(localStorage.getItem('cart')) || [];
const cartItemsElement = document.getElementById('cart-items');
if (cart.length === 0) {
cartItemsElement.innerHTML = '<p>Votre panier est vide</p>';
return;
}
cartItemsElement.innerHTML = '';
cart.forEach((item, index) => {
const itemElement = document.createElement('div');
itemElement.className = 'cart-item';
// Créer une chaîne de texte pour les variations
const variationsText = item.variations ?
Object.entries(item.variations)
.map(([key, value]) => `<span class="variation-item">${key}: ${value}</span>`)
.join(' ') : '';
itemElement.innerHTML = `
<img src="${item.image}" alt="${item.name}" width="80">
<div class="item-details">
<h3>${item.name}</h3>
<p class="price">${item.price}€</p>
${variationsText ? `<div class="selected-variations">${variationsText}</div>` : ''}
</div>
<div class="quantity-controls">
<button class="decrease-btn" data-index="${index}">-</button>
<input type="number" min="1" value="${item.quantity}" class="quantity-input" data-index="${index}">
<button class="increase-btn" data-index="${index}">+</button>
</div>
<p class="item-total">${(item.price * item.quantity).toFixed(2)}€</p>
<button class="remove-btn" data-index="${index}">Supprimer</button>
`;
cartItemsElement.appendChild(itemElement);
});
// Ajouter les écouteurs d'événements pour les boutons
setupCartEventListeners();
}
// Initialiser le panier au chargement de la page
document.addEventListener('DOMContentLoaded', renderCart);
// Fonction pour configurer les écouteurs d'événements (à implémenter)
function setupCartEventListeners() {
// Code pour gérer les boutons +/- et supprimer
}
</script>
</Layout>
Cette approche vous permet de :
- Afficher les variations disponibles pour chaque produit
- Permettre aux utilisateurs de sélectionner les options souhaitées
- Stocker ces sélections dans le panier
- Afficher les variations sélectionnées dans le panier
Vous pouvez adapter ce code selon vos besoins spécifiques et le style de votre site.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@spiral sparrow voici mon shema:
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders';
const products = defineCollection({
loader: glob({
pattern: '**/*.json',
base: "./src/content/products",
}),
schema: z.object({
image: z.string().url(),
name: z.string(),
description: z.string(),
price: z.number(),
category: z.enum(['Électronique', 'Mode', 'Maison & Jardin', 'Beauté & Santé', 'Sport', 'Jeux & Jouets', 'Alimentation & Boissons']),
status: z.enum(['En stock', 'Indisponible', 'Disponible fournisseur']),
variations: z.array(
z.object({ title: z.string(), value: z.array(z.string()) })
).optional(),
}),
});
export const collections = { products };
Let me check the knowledge base for you again. One moment! :books:
Votre schéma pour la collection de produits est bien structuré. Vous utilisez correctement le nouveau Content Layer API d'Astro avec le loader glob() pour charger vos fichiers JSON depuis le répertoire src/content/products.
Voici une analyse de votre schéma :
- Vous utilisez
glob()pour charger tous les fichiers JSON dans le dossier spécifié - Vous avez défini un schéma avec Zod qui inclut :
- Des champs obligatoires (image, name, description, price)
- Des énumérations pour category et status
- Un tableau optionnel de variations
C'est une bonne approche pour une collection de produits e-commerce. Le schéma est bien typé et vous permettra de bénéficier de la validation et de l'autocomplétion TypeScript.
Pour utiliser cette collection dans votre site, vous pourrez récupérer vos produits avec :
import { getCollection } from 'astro:content';
const products = await getCollection('products');
Et pour un produit spécifique :
import { getEntry } from 'astro:content';
const product = await getEntry('products', 'nom-du-fichier-sans-extension');
Votre structure de variations est également bien pensée, permettant de stocker différentes options comme taille, couleur, etc. Pour chaque variation, vous avez un titre et un tableau de valeurs possibles.
Si vous avez besoin d'ajouter d'autres champs à l'avenir, vous pourrez facilement étendre ce schéma.
Y a-t-il quelque chose de spécifique que vous aimeriez savoir sur l'utilisation de ce schéma dans votre projet Astro ?
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@teal arrow Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@spiral sparrow comment afficher les données
Let me check the knowledge base for you again. One moment! :books:
Pour afficher les données de votre collection de produits dans Astro, vous pouvez utiliser les fonctions getCollection ou getEntry de l'API Content Collections. Voici comment procéder:
Afficher une liste de produits
Pour afficher tous vos produits sur une page:
---
import { getCollection } from 'astro:content';
// Récupérer tous les produits
const products = await getCollection('products');
---
<h1>Nos produits</h1>
<div class="products-grid">
{products.map(product => (
<div class="product-card">
<img src={product.data.image} alt={product.data.name} />
<h2>{product.data.name}</h2>
<p class="price">{product.data.price}€</p>
<p class="status">{product.data.status}</p>
<p class="category">{product.data.category}</p>
<a href={`/products/${product.slug}`}>Voir détails</a>
</div>
))}
</div>
Afficher un produit individuel avec ses variations
Pour une page de détail de produit:
---
import { getEntry } from 'astro:content';
// Récupérer le produit depuis l'URL
const { slug } = Astro.params;
const product = await getEntry('products', slug);
if (!product) {
return Astro.redirect('/404');
}
---
<div class="product-detail">
<img src={product.data.image} alt={product.data.name} />
<div class="product-info">
<h1>{product.data.name}</h1>
<p class="price">{product.data.price}€</p>
<p class="status">{product.data.status}</p>
<p class="description">{product.data.description}</p>
{/* Afficher les variations si elles existent */}
{product.data.variations && (
<div class="variations">
{product.data.variations.map((variation) => (
<div class="variation-group">
<h3>{variation.title}</h3>
<div class="variation-options">
{variation.value.map((option) => (
<label class="option">
<input
type="radio"
name={variation.title}
value={option}
/>
<span>{option}</span>
</label>
))}
</div>
</div>
))}
</div>
)}
<button id="add-to-cart">Ajouter au panier</button>
</div>
</div>
## Filtrer les produits par catégorie
Pour afficher les produits d'une catégorie spécifique:
```astro
---
import { getCollection } from 'astro:content';
// Récupérer la catégorie depuis l'URL
const { category } = Astro.params;
// Récupérer tous les produits
const allProducts = await getCollection('products');
// Filtrer par catégorie
const products = allProducts.filter(product =>
product.data.category === category
);
---
<h1>Produits dans la catégorie {category}</h1>
<div class="products-grid">
{products.map(product => (
<div class="product-card">
<img src={product.data.image} alt={product.data.name} />
<h2>{product.data.name}</h2>
<p class="price">{product.data.price}€</p>
<a href={`/products/${product.slug}`}>Voir détails</a>
</div>
))}
</div>
Ces exemples vous montrent comment afficher vos données de produits dans différents contextes. Vous pouvez les adapter selon vos besoins spécifiques et le design de votre site.