SPECKIT

Redactor de Especificaciones

SPEC-047 ✓ NUEVA Lista para implementación

Card de Producto — Listado de Tienda

Componente de presentación reutilizable para el catálogo de productos. Soporta estado sin imagen, interacción hover y acción de carrito.

Descripción
Objetivo
Mostrar un producto del catálogo de forma visual y accionable, permitiendo al usuario añadirlo al carrito directamente desde el listado sin navegar a la PDP.
Ámbito
Página de listado de tienda (/shop) y colecciones. Excluye la página de detalle de producto (PDP).
Etiquetas
UI Interacción A11y Rendimiento
Requisitos funcionales
RF-01 Logo marca
El logo de la marca se muestra en la esquina superior izquierda de la card. Tamaño: 32×32px. Z-index sobre la imagen. Contraste mínimo WCAG AA.
RF-02 Imagen producto
Imagen principal del producto con relación de aspecto 1:1 (cuadrado). object-fit: cover. Si la imagen falla o no existe, mostrar placeholder gris (#2e3249) con icono SVG centrado.
RF-03 Nombre
Nombre del producto: font-size: 14px, font-weight: 600, máximo 2 líneas con text-overflow: ellipsis.
RF-04 Precio
Precio formateado con moneda (Intl.NumberFormat). font-size: 18px, font-weight: 700, color --accent2. Si hay precio tachado (oferta) mostrarlo en gris a 14px.
RF-05 CTA Carrito
Botón "Añadir al carrito" a ancho completo. Estados: default → loading (spinner + "Añadiendo…") → success ("✓ Añadido", 1.5s) → vuelta a default. Si sin stock: desactivado + texto "Agotado".
RF-06 Hover
Al hacer hover (escritorio): transform: translateY(-4px), box-shadow: 0 8px 24px rgba(0,0,0,.35). Transición: all 200ms ease. Equivalente :focus-visible para teclado.
Criterios de aceptación
DADO un producto con imagen y en stock, CUANDO el usuario ve la card en el listado, ENTONCES se muestran logo, imagen, nombre, precio y botón activo.
DADO un producto sin imagen, CUANDO la card se renderiza, ENTONCES el área de imagen muestra el placeholder gris con icono.
DADO un producto agotado, CUANDO se renderiza el botón, ENTONCES el botón aparece desactivado con texto "Agotado" y no es clickable.
DADO que el usuario hace hover sobre la card en escritorio, CUANDO el cursor entra en el área, ENTONCES la card sube 4px y aparece sombra en 200ms.
DADO que el usuario pulsa "Añadir al carrito", CUANDO la llamada a la API está en curso, ENTONCES el botón muestra spinner + "Añadiendo…" y está desactivado.
DADO que la API confirma el añadido, CUANDO la respuesta es 200, ENTONCES el botón muestra "✓ Añadido" durante 1.5s y vuelve al estado default.
Casos límite

Nombre muy largo

Nombres de más de 60 caracteres: truncar a 2 líneas con ellipsis. No romper el layout.

Imagen rota (error 404)

Event onError en <img> activa el placeholder gris automáticamente.

Error en API de carrito

Si la llamada falla: botón vuelve a default y se muestra toast de error (no definido en esta spec; ver toast-system).

Precio sin decimales

Intl.NumberFormat con minimumFractionDigits: 0 para precios enteros. Nunca mostrar €20.00 → mostrar €20.

Móvil / touch

El efecto hover no aplica en dispositivos táctiles (@media (hover: none)). El botón conserva tamaño mínimo de 44×44px (touch target WCAG).

Sin logo de marca

Si el logo no está disponible: ocultar el espacio reservado (no placeholder). El nombre del producto asume la identificación.

Dependencias y referencias
Tokens de diseño
--accent2 (precio), --surface (fondo card), --border (borde), --text (nombre)
Specs relacionadas
toast-system · cart-api · image-optimizer
APIs
POST /api/cart/add — body: {"variant_id": string, "qty": 1} — responde 200 o 4xx
Accesibilidad
WCAG 2.1 AA · role="article" en la card · aria-label en botón con nombre de producto · aria-disabled cuando agotado