NutriTrack
Design System
Guía de implementación para equipos de diseño y desarrollo. Componentes, tokens y criterios de accesibilidad WCAG 2.2 AA.
Tokens de Color
Paleta semántica centralizada. Usar siempre el token; nunca valores hex crudos en componentes.
Intención del diseño: NutriTrack comunica energía vital y confianza profesional. El amarillo primario (#FECE14) activa atención sin saturar; el negro secundario ancla estructura y autoridad. Toda la paleta parte de estos dos polos.
Tipografía
Escala mobile-first compacta. Poppins para todo el producto; IBM Plex Mono para labels, datos y código.
Escala de Espaciado
Sistema modular basado en múltiplos de 4px. Usar siempre tokens; nunca valores ad hoc.
Bordes y Sombras
Radios coherentes comunican jerarquía visual. Sombras usadas con moderación para profundidad.
radius-sm (4px)Cards →
radius-lg (12px)Chips/badges →
radius-full
shadow-smTarjetas en hover →
shadow-mdModales, dropdowns →
shadow-lg
Inputs de Formulario
Los formularios son el corazón del flujo de datos clínicos. Cada estado comunica validación de forma inequívoca.
| Estado | Border | Ring (box-shadow) | Comportamiento |
|---|---|---|---|
| Default | --color-border 1.5px |
Ninguno | Placeholder visible, cursor text |
| Focus | --color-secondary 1.5px |
0 0 0 3px rgba(17,24,39,0.08) | MUST focus-visible, no outline nativo |
| Error | --color-danger 1.5px |
0 0 0 3px rgba(220,38,38,0.08) | Mensaje de error bajo el input, aria-invalid="true" |
| Success | --color-success 1.5px |
0 0 0 3px rgba(22,163,74,0.08) | Mensaje de confirmación, aria-describedby |
| Disabled | --color-border |
Ninguno | bg-alt, cursor: not-allowed, aria-disabled |
Badges y Chips de Estado
Indicadores semánticos de estado. No usar color como único diferenciador; siempre acompañar con texto o icono.
| Chip | Uso en NutriTrack | Token Background | Token Text |
|---|---|---|---|
| Activo | Paciente con seguimiento activo, plan vigente | #DCFCE7 |
#15803D |
| Pendiente | Consulta programada, pago pendiente | #FEF3C7 |
#B45309 |
| Inactivo | Paciente sin actividad > 30 días | --color-bg-alt |
--color-text-muted |
| Alerta | Objetivo no cumplido, dato fuera de rango | #FEE2E2 |
#B91C1C |
Tarjeta de Paciente
Componente central del dashboard. Muestra estado, progreso y próxima cita en una vista compacta y scannable.
| Elemento | Token / Especificación | Regla |
|---|---|---|
| Barra de acento (top) | 3px sólido · color según estado (primary / warning / danger) | MUST |
| Avatar | 44×44px, border-radius: 50%, iniciales del paciente, background semántico | MUST include aria-label |
| Nombre | font-weight: 700, font-size: 1rem, color: --color-text | MUST |
| Metadatos | font-mono, font-size: 0.75rem, color: --color-text-muted | SHOULD |
| Barra de progreso | height: 6px, radius-full, color según estado | MUST incluir label de porcentaje |
| Footer | border-top: 1px --color-border, padding-top: --space-3 | SHOULD |
| Hover | shadow-md, border-color: --color-secondary, translateY(-1px) | MUST |
| Focus-visible | outline: 3px --color-primary, outline-offset: 2px | MUST |
Accesibilidad WCAG 2.2 AA
Cada componente debe satisfacer los criterios siguientes. Son testables en code review.
| Criterio | Nivel | Aplicación |
|---|---|---|
| Contraste texto normal ≥ 4.5:1 | AA | Todo el cuerpo de texto |
| Contraste texto grande ≥ 3:1 | AA | H1, H2 (≥18pt o 14pt bold) |
| Focus visible en todos los interactivos | AA 2.4.11 | Botones, inputs, cards, links |
| No depender solo de color para el estado | AA 1.4.1 | Chips, campos de error/success |
| Labels descriptivos en todos los inputs | AA 1.3.1 | Formularios de registro y seguimiento |
| aria-invalid en campos de error | AA 4.1.3 | Input con estado error |
| role + aria-label en cards interactivas | AA 4.1.2 | Patient Card (tabindex, role="button") |
| Componente | Teclas | Comportamiento |
|---|---|---|
| Botón | Enter / Space | Activar acción |
| Input | Tab / Shift+Tab | Navegar entre campos |
| Patient Card | Enter | Abrir perfil del paciente |
| Formulario | Escape | Cancelar / cerrar modal |
| Todos | Tab | Orden lógico de DOM, nunca trampa de foco |
Regla de prioridad: Cuando exista conflicto entre estética y accesibilidad, la accesibilidad prevalece sin excepción. Documentar el conflicto y proponer una alternativa en el PR.
Anti-patrones Prohibidos
Implementaciones incorrectas documentadas. Incluyen guía de migración para código existente inconsistente.
| Patrón incorrecto existente | Migración recomendada | Prioridad |
|---|---|---|
Texto blanco sobre fondo #FECE14 |
Cambiar color de texto a --color-secondary (#000) |
P0 — Urgente |
| outline: none sin focus ring alternativo | Añadir :focus-visible { outline: 3px solid var(--color-primary); } |
P0 — Urgente |
| Inputs sin label visible (solo placeholder) | Añadir <label> vinculado via for / aria-label |
P1 — Alta |
| Valores px hardcoded en padding/margin | Sustituir por tokens de espaciado (--space-*) |
P2 — Normal |
Checklist de QA
Ejecutar en cada PR que toque componentes de UI. No merguear si algún ítem P0 está sin marcar.
-
✓a11y P0Contraste de color verificadoTodo el texto visible tiene ratio ≥ 4.5:1 (normal) o ≥ 3:1 (grande). Usar WebAIM Contrast Checker.
-
✓a11y P0Focus ring visible en todos los elementos interactivosNavegar con Tab en el componente nuevo. Cada elemento focusable debe mostrar outline de 3px #FECE14 o equivalente.
-
✓código P1Solo tokens de color, no valores hex crudosgrep -r "#[0-9A-Fa-f]{6}" src/components/ no debe devolver resultados nuevos.
-
visual P1Espaciado usando tokens --space-*No se aceptan valores de padding/margin fuera de la escala 4/8/12/16/24/32.
-
a11y P0Todos los inputs tienen label accesible<label for="..."> o aria-label o aria-labelledby presentes. Nunca solo placeholder.
-
a11y P0Estados de error usan aria-invalid y aria-describedbyScreen reader debe anunciar el error. Testear con VoiceOver (Mac) o NVDA (Windows).
-
a11y P1Botones deshabilitados usan aria-disabled="true" + pointer-events: noneNo usar solo el atributo HTML disabled si el botón es un <a> o div.
-
visual P2Tipografía respeta la escala definidaNo se usan tamaños de fuente fuera de la escala. font-weight limitado a los pesos definidos (100–900).
-
a11y P1Patient Card incluye aria-label descriptivoaria-label="Ver perfil de [Nombre Paciente]". role="button" si es interactiva.
-
contenido P2Textos no son ambiguos como etiqueta de acciónEvitar "Click aquí", "Ver más", "OK" sin contexto. Usar "Ver plan de María García", "Confirmar eliminación".
-
visual P1Componente responsive: probado en 375px y 1440pxLa Patient Card debe mantenerse legible en mobile. Grids deben colapsar correctamente.
-
a11y P1Iconos decorativos tienen aria-hidden="true"Iconos que acompañan texto deben ser opacos para screen readers.
Versión y mantenimiento: Este documento se considera fuente de verdad a partir de v1.0.0. Cualquier desviación acordada debe documentarse en el CHANGELOG del design system antes de implementarse en producción. Contacto: equipo de diseño + #design-system en Slack.