feat(ADM-018): completed feature
This commit is contained in:
294
project/specs-admin/000-foundation/DESIGN.md
Normal file
294
project/specs-admin/000-foundation/DESIGN.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# ADM-001 / ADM-002 / ADM-003 — Design
|
||||
|
||||
## 1. Design System
|
||||
|
||||
### Palette
|
||||
|
||||
| Token | Hex | Uso |
|
||||
|--------------------|-----------|------------------------------|
|
||||
| `--color-primary` | `#2D6A4F` | Acciones principales |
|
||||
| `--color-primary-hover` | `#1B4332` | Hover primary |
|
||||
| `--color-danger` | `#DC2626` | Acciones destructivas |
|
||||
| `--color-warning` | `#D97706` | Estados de atención |
|
||||
| `--color-success` | `#059669` | Confirmaciones, éxito |
|
||||
| `--color-bg` | `#F9FAFB` | Fondo de página |
|
||||
| `--color-surface` | `#FFFFFF` | Tarjetas, panels |
|
||||
| `--color-border` | `#E5E7EB` | Bordes |
|
||||
| `--color-text` | `#111827` | Texto principal |
|
||||
| `--color-muted` | `#6B7280` | Texto secundario |
|
||||
|
||||
### Typography
|
||||
|
||||
- **Headings**: `Playfair Display` (fuente de marca) o fallback `serif`
|
||||
- **Body/UI**: `Inter` (fuente del storefront) o fallback `sans-serif`
|
||||
- **Monospace** (SKU, IDs): `font-mono`
|
||||
|
||||
### Spacing
|
||||
|
||||
- Base unit: 4px
|
||||
- Consistent: 4, 8, 12, 16, 24, 32, 48px
|
||||
|
||||
### Border radius
|
||||
|
||||
- Buttons/inputs: `rounded-lg` (8px)
|
||||
- Cards: `rounded-xl` (12px)
|
||||
- Modals: `rounded-2xl` (16px)
|
||||
|
||||
---
|
||||
|
||||
## 2. Login Page Design
|
||||
|
||||
### Desktop (≥1024px)
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ │
|
||||
│ 🌿 MercadoDeVida │
|
||||
│ ───────────────── │
|
||||
│ │
|
||||
│ Iniciar sesión │
|
||||
│ │
|
||||
│ Email │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ tu@email.com │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ Contraseña │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ •••••••• │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ Iniciar sesión │ │
|
||||
│ └─────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Centrado vertical y horizontalmente
|
||||
- Card blanca con sombra suave
|
||||
- Logo de marca
|
||||
- Inputs: border gris, focus ring verde
|
||||
- Botón: full-width, verde primary
|
||||
|
||||
### Mobile (< 768px)
|
||||
- Padding lateral 24px
|
||||
- Mismo layout, inputs 100% del card
|
||||
|
||||
### States
|
||||
|
||||
**Loading**: Botón deshabilitado con spinner
|
||||
**Error**: Card con border rojo, mensaje debajo del form
|
||||
**Success**: Redirect inmediato
|
||||
|
||||
---
|
||||
|
||||
## 3. Admin Shell Design
|
||||
|
||||
### Desktop (≥1024px)
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 🌿 MercadoDeVida Admin admin@mdv.es [Logout] │
|
||||
├──────────┬──────────────────────────────────────────────────┤
|
||||
│ │ │
|
||||
│ Dashboard│ [Page Title] [+ Nueva acción] │
|
||||
│ 📦 Productos│ ─────────────────────────────────────────── │
|
||||
│ 🧾 Pedidos│ │
|
||||
│ 📊 Inventario│ [Content Area] │
|
||||
│ 👥 Clientes│ │
|
||||
│ 🏷 Categorías│ │
|
||||
│ 🏷 Marcas│ │
|
||||
│ 🏷 Promociones│ │
|
||||
│ ⭐ Reseñas│ │
|
||||
│ 📄 CMS │ │
|
||||
│ ⚙ Ajustes│ │
|
||||
│ │ │
|
||||
│ ├──────────────────────────────────────────────────┤
|
||||
│ │ © 2026 MercadoDeVida. Panel de administración. │
|
||||
└──────────┴──────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Sidebar: 240px fija, bg white, border-right
|
||||
- Header: 64px, bg white, sticky top
|
||||
- Content: bg `--color-bg`, padding 32px
|
||||
- Footer: minimal copyright
|
||||
|
||||
### Tablet (768px – 1023px)
|
||||
- Sidebar colapsa a 64px (solo iconos)
|
||||
- Toggle para expandir
|
||||
|
||||
### Mobile (< 768px)
|
||||
- Sidebar como drawer overlay desde la izquierda
|
||||
- Hamburger button en header
|
||||
- Overlay oscuro al abrir drawer
|
||||
|
||||
### Navigation Items
|
||||
|
||||
| Icon | Label | Permission | Badge (opcional) |
|
||||
|------|------------|-------------------|------------------|
|
||||
| 📊 | Dashboard | (dashboard) | |
|
||||
| 📦 | Productos | products.read | |
|
||||
| 🧾 | Pedidos | orders.read | 3 (pendientes) |
|
||||
| 📊 | Inventario | inventory.read | |
|
||||
| 👥 | Clientes | customers.read | |
|
||||
| 🏷️ | Categorías | categories.read | |
|
||||
| 🏷️ | Marcas | brands.read | |
|
||||
| 🏷️ | Promociones| promotions.read | |
|
||||
| ⭐ | Reseñas | reviews.read | 5 (pendientes) |
|
||||
| 📄 | CMS | cms.read | |
|
||||
| ⚙️ | Ajustes | (settings) | |
|
||||
|
||||
Active state: bg primary/10, text primary, left border 3px primary
|
||||
|
||||
---
|
||||
|
||||
## 4. Status Colors (Accessible)
|
||||
|
||||
| Status | Color | Pattern |
|
||||
|-------------|--------|------------------|
|
||||
| Active | Green | `bg-green-100 text-green-800` |
|
||||
| Inactive | Gray | `bg-gray-100 text-gray-600` |
|
||||
| Pending | Amber | `bg-amber-100 text-amber-800` |
|
||||
| Paid | Green | `bg-green-100 text-green-800` |
|
||||
| Processing | Blue | `bg-blue-100 text-blue-800` |
|
||||
| Shipped | Indigo | `bg-indigo-100 text-indigo-800` |
|
||||
| Delivered | Green | `bg-green-100 text-green-800` |
|
||||
| Cancelled | Red | `bg-red-100 text-red-800` |
|
||||
| Refunded | Purple | `bg-purple-100 text-purple-800` |
|
||||
|
||||
⚠️ Usar ALWAYS el label junto al color, nunca solo el color.
|
||||
|
||||
---
|
||||
|
||||
## 5. Component Library (Admin Primitives)
|
||||
|
||||
### Button
|
||||
|
||||
```tsx
|
||||
<Button variant="primary" size="md" loading={saving} onClick={save}>
|
||||
Guardar
|
||||
</Button>
|
||||
|
||||
<Button variant="danger" onClick={confirmDelete}>
|
||||
Eliminar
|
||||
</Button>
|
||||
|
||||
<Button variant="ghost" onClick={cancel}>
|
||||
Cancelar
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Input / Textarea
|
||||
|
||||
```tsx
|
||||
<Input
|
||||
label="Nombre del producto"
|
||||
value={name}
|
||||
onChange={setName}
|
||||
error={errors.name}
|
||||
required
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
label="Descripción"
|
||||
value={description}
|
||||
onChange={setDescription}
|
||||
rows={4}
|
||||
/>
|
||||
```
|
||||
|
||||
### DataTable
|
||||
|
||||
Props: columns, data, pagination, onSort, onFilter, loading, empty, error
|
||||
|
||||
```tsx
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={products}
|
||||
pagination={{ page, total, onPageChange }}
|
||||
loading={isLoading}
|
||||
/>
|
||||
```
|
||||
|
||||
### Dialog (Confirmation)
|
||||
|
||||
```tsx
|
||||
<Dialog
|
||||
open={confirming}
|
||||
title="Confirmar eliminación"
|
||||
description="Esta acción no se puede deshacer."
|
||||
confirmLabel="Eliminar"
|
||||
variant="danger"
|
||||
onConfirm={delete}
|
||||
onCancel={() => setConfirming(false)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Badge
|
||||
|
||||
```tsx
|
||||
<Badge variant="success">Activo</Badge>
|
||||
<Badge variant="warning">Pendiente</Badge>
|
||||
<Badge variant="error">Cancelado</Badge>
|
||||
```
|
||||
|
||||
### Skeleton
|
||||
|
||||
```tsx
|
||||
<TableSkeleton rows={10} columns={4} />
|
||||
<FormSkeleton fields={5} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Error States
|
||||
|
||||
| State | Visual | Action |
|
||||
|----------|-------------------------------------|-------------------|
|
||||
| Loading | Skeleton que refleja la estructura | Ninguna |
|
||||
| Empty | Ilustración + "No hay datos" | CTA si aplica |
|
||||
| Error | Icono error + mensaje + retry btn | Botón retry |
|
||||
| 403 | Icono candado + "Sin permisos" | Volver atrás |
|
||||
| 404 | Icono búsqueda + "No encontrado" | Volver atrás |
|
||||
|
||||
---
|
||||
|
||||
## 7. Toast Notifications
|
||||
|
||||
```tsx
|
||||
// Success
|
||||
toast.success('Producto guardado correctamente');
|
||||
|
||||
// Error
|
||||
toast.error('Error al guardar. Intenta de nuevo.');
|
||||
|
||||
// Warning
|
||||
toast.warning('Este campo es requerido.');
|
||||
|
||||
// Position: top-right
|
||||
// Duration: 4s
|
||||
// Dismissible
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Responsive Strategy
|
||||
|
||||
| Breakpoint | Admin Layout | Tables | Forms |
|
||||
|------------|--------------------------|-------------------------|------------------|
|
||||
| 1440px | Sidebar 240px | All columns | Full layout |
|
||||
| 1280px | Sidebar 240px | All columns | Full layout |
|
||||
| 1024px | Sidebar collapsed 64px | Scroll horizontal | Full layout |
|
||||
| 768px | Sidebar as drawer | Cards, no table headers | Stacked fields |
|
||||
| 430px | Sidebar as drawer | Cards | Full width inputs|
|
||||
|
||||
---
|
||||
|
||||
## 9. Accessibility
|
||||
|
||||
- All interactive elements keyboard-navigable
|
||||
- Focus ring visible en todos los elementos
|
||||
- ARIA labels en iconos sin texto
|
||||
- Error messages linked via `aria-describedby`
|
||||
- Color contrast ≥ 4.5:1 para texto
|
||||
- Tables con `scope="col"` headers
|
||||
- Dialogs con `role="dialog"` y focus trap
|
||||
Reference in New Issue
Block a user