Documentación de patrones de diseño, accesibilidad y mejores prácticas aplicadas en la capa visual de Finward (auditoría Marzo 2025).
- Mobile-First: El 90% de los usuarios registran gastos desde móvil. La UI está optimizada para uso con una sola mano.
- Menos fricción: Registrar un gasto en ≤3 clics cuando es posible.
- Feedback inmediato: Estados de carga, validación inline y micro-interacciones en cada acción.
Componente reutilizable para acciones primarias. Usar siempre en lugar de <button> nativo para formularios.
- Variants:
primary,secondary,outline,ghost,danger,success - Sizes:
sm(36px),md(44px min),lg(48px min) - Props clave:
isLoading,fullWidth,leftIcon,rightIcon
<Button variant="primary" size="lg" isLoading={isPending} fullWidth>
Guardar
</Button>Touch targets: Botones principales deben usar size="md" o size="lg" (mínimo 44px) para cumplir WCAG.
Componente unificado que usa Lucide React como única librería de iconos. Mapea nombres legacy (Material Symbols) a iconos Lucide para consistencia y aspecto premium.
import { Icon } from '@/components/Icon';
<Icon name="add" size={20} />
<Icon name={category.icon} size={24} className="text-app-primary" />- quickCount: Muestra las primeras N categorías como botones rápidos (1 clic) encima del grid completo.
- Botones del grid con
min-h-[72px]para touch. - Quick categories con
min-h-[44px].
Mensaje de error inline bajo campos de formulario. Usar junto con validación.
<FieldError message={fieldErrors.amount} />- Inline: Errores debajo de cada campo con
FieldError. - Toast: Errores de API o mensajes globales con
toastError. - Estado:
fieldErrors: Record<string, string>en formularios. - Limpiar errores al cambiar valor:
clearFieldError('fieldName').
| Elemento | Mínimo | Implementación |
|---|---|---|
| Botones primarios | 44×44px | Button size="md" o "lg" |
| Selects | 44px alto | min-h-[44px] h-12 |
| Categorías grid | 72px | min-h-[72px] |
| Teclado numérico | 52px | min-h-[52px] en cada tecla |
Definidas en frontend/src/index.css:
- animate-fade-in: Entrada suave (opacity + translateY)
- animate-scale-in: Modal/sheet (scale 0.96→1)
- animate-shake: Error de validación (feedback visual)
- SwipeableBottomSheet: Bottom sheet en móvil, modal centrado en desktop (≥1024px).
- DeleteConfirmationSheet: Confirmación destructiva con niveles (
normal,warning,critical). - Nunca usar
window.confirm(); usarDeleteConfirmationSheet.
- FAB → Tipo (Gasto/Ingreso/Transf.)
- Monto con NumericKeypad
- Categoría rápida (6 primeras) o grid
- Concepto, Cuenta, Fecha
- Confirmar
- Saldo hero
- Nombre
- Tipo (grid de 5)
- Si Crédito: campos específicos
- Confirmar
- Filtros: Por tipo (CRYPTO, STOCK, otros), ganadores/perdedores (% positivo/negativo).
- Ordenación: Por valor, porcentaje o nombre.
- Búsqueda: Por nombre o ticker.
- Gráfico: Bar chart con valor de cada activo.
- Formulario (CRYPTO): Autocompletado de ticker vía CoinGecko; placeholders contextuales; ticker normalizado a minúsculas.
- Formulario (STOCK): Placeholders específicos (ej. AAPL, MSFT).
- Detalle: Enlace externo a CoinGecko cuando el activo tiene ticker crypto.
- Empty states: Mensajes diferenciados según contexto (lista vacía, sin resultados de búsqueda).
- docs/PERFORMANCE.md - Optimizaciones de rendimiento
- backend/docs/ARCHITECTURE.md - Arquitectura general