diff --git a/CLAUDE.md b/CLAUDE.md index f235e90..cbd11ee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,6 +5,49 @@ --- +## ⚠️ Reglas de Marca — NO NEGOCIABLES (Sprint 1.5+) + +Estas reglas aplican a TODO string que aparezca en código, PDFs, CSVs, tests y documentación. + +### 1. Ortografía de "InQ" — SIEMPRE I-n-Q + +``` +✅ InQ ← correcto +✅ InQuality ← correcto (nombre completo) +✅ InQ ROI ← nombre del producto + +❌ INQ ← bug +❌ Inq ← bug +❌ inq ← bug +❌ inQ ← bug +``` + +Cualquier desviación es un bug que debe corregirse antes de hacer commit. + +### 2. Nombre del producto + +`InQ ROI` — nombre de trabajo para Sprint 1.5. Se reemplazará en Sprint 3-4. No debatir el nombre ahora. + +### 3. Color protagonista + +``` +Primario: #F59845 (naranja InQ) +Gradiente: #F59845 → #ED3E8F (naranja → magenta InQ) +``` + +El gradiente se usa SOLO en KPI Hero y banners principales. +**NO usar morado de CONCILIA** (`#572FA2`, `#CB1889`) en este producto. + +### 4. Footer de PDFs + +Tagline obligatorio: `"Powered by InQuality"` — en todos los footers de PDF, siempre. + +### 5. Rol del consultor + +Si aparece un nombre de consultor en algún campo, es como "consultor responsable", no como "creador" ni "founder" del producto. + +--- + ## Identidad del Proyecto **Nombre de trabajo**: Process Cost Platform (nombre comercial por definir) @@ -231,4 +274,15 @@ npx playwright test # tests E2E (Playwright headless) - Casos de uso confirmados: - Análisis de costos operativos en consultoría de procesos - **Pre-venta de proyectos de automatización con cálculo de ROI** (caso estrella del Sprint 1) -- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa \ No newline at end of file +- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa + +--- + +## Reglas de marca NO NEGOCIABLES + +- "InQ" siempre se escribe I-n-Q (mayúscula-minúscula-mayúscula) +- Color protagonista: naranja #F59845 +- Gradiente identidad: #F59845 → #ED3E8F +- NO usar morado CONCILIA (#572FA2, #CB1889) +- Footer obligatorio: "Powered by InQuality" +- No promover a Marcos como creador \ No newline at end of file diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md new file mode 100644 index 0000000..fe99d63 --- /dev/null +++ b/DESIGN_SYSTEM.md @@ -0,0 +1,330 @@ +# InQ ROI — Sistema de Diseño + +> Documento de referencia visual para Sprint 2+. +> Fuente de verdad para la paleta, tipografía y componentes. +> Actualizar en cada sprint que modifique la identidad visual. + +--- + +## 1. Identidad de Marca + +### Nombre del producto +**InQ ROI** — herramienta interna de InQuality para cuantificación de ROI de automatización. + +### Regla de ortografía (NO NEGOCIABLE) +``` +✅ InQ ← I mayúscula, n minúscula, Q mayúscula +✅ InQuality ← nombre completo +❌ INQ / Inq / inq / inQ ← cualquiera es bug +``` + +### Tagline en footers PDF +`"Powered by InQuality"` — obligatorio en todos los footers de PDF. + +--- + +## 2. Paleta Cromática + +### 2.1 InQ Orange — Color protagonista + +| Token Tailwind | CSS Var | Hex | HSL | Uso | +|---|---|---|---|---| +| `bg-inq-orange` | `--inq-orange` | `#F59845` | 28° 90% 62% | Principal: logo, KPIs hero, CTAs primarios | +| `bg-inq-orange-dark` | `--inq-orange-dark` | `#B45309` | 34° 93% 37% | Texto sobre fondos claros, hover de CTAs | +| `bg-inq-orange-light` | `--inq-orange-light` | `#FEF3E2` | 36° 95% 88% | Fondos de KPI cards | +| `bg-inq-orange-lighter` | `--inq-orange-lighter` | `#FFF8ED` | 36° 100% 94% | Fondos de banner narrativo, hover sutiles | + +### 2.2 InQ Magenta — Gradiente identidad + +| Token Tailwind | CSS Var | Hex | Uso | +|---|---|---|---| +| `bg-inq-magenta` | `--inq-magenta` | `#ED3E8F` | Segundo color del gradiente identidad | + +#### Gradiente identidad +```css +background: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%); +``` + +**Uso exclusivo:** KPI Hero "Ahorro proyectado" en PDF y web. NUNCA en bordes, separadores ni fondos secundarios. + +### 2.3 Semánticos + +| Token Tailwind | CSS Var | Hex | Uso | +|---|---|---|---| +| `bg-success` | `--color-success` | `#16A34A` | Ahorros positivos, payback alcanzado | +| `bg-success-light` | `--color-success-light` | `#F0FDF4` | Fondos de mensajes positivos | +| `bg-warning` | `--color-warning` | `#F59E0B` | Advertencias, sección transparencia | +| `bg-warning-bg` | `--color-warning-bg` | `#FFFBEB` | Fondo de sección transparencia | +| `bg-destructive` / `--color-danger` | — | `#EF4444` | Costos altos, valores negativos | +| `--color-danger-light` | — | `#FEE2E2` | Fondos de heatmap alto costo | + +### 2.4 Heatmap — Paleta saturada (FIJA hasta Sprint 3-4) + +| Token Tailwind | Hex | RGB | Uso | +|---|---|---|---| +| `bg-heatmap-low` | `#10B981` | (16, 185, 129) | Actividades de bajo costo | +| `bg-heatmap-mid` | `#F59E0B` | (245, 158, 11) | Actividades de costo medio | +| `bg-heatmap-high` | `#EF4444` | (239, 68, 68) | Actividades de alto costo | + +#### Decisión sobre paleta de heatmap + +**Se mantiene saturada** (verde-ámbar-rojo) en lugar de la variante pastel del brief por dos razones: + +1. **Tests E2E calibrados**: los análisis de píxeles del heatmap (`export-pdf.spec.ts`, `validate-dod-etapa4.spec.ts`) tienen umbrales calibrados para estos colores. Cambiar la paleta requiere recalibrar todos esos umbrales. + +2. **Visibilidad en pantallas grandes**: el producto se usa en talleres y charlas InQuality proyectadas en pantalla. Los colores saturados mantienen contraste a distancia. Los pasteles se "lavan" a 3+ metros. + +**Revisión programada**: Sprint 3-4 con feedback real de uso en talleres. + +**Invariante crítica**: los valores de `tailwind.config.js` `heatmap.*` DEBEN coincidir con las constantes `HEATMAP_LOW/MID/HIGH` en `src/lib/colors.ts`. Si se modifica uno, debe actualizarse el otro. + +### 2.5 Neutrales + +| Hex | Tailwind equivalente | Uso | +|---|---|---| +| `#0F172A` | `slate-900` | Títulos, números importantes | +| `#475569` | `slate-600` | Texto del cuerpo | +| `#64748B` | `slate-500` | Labels, metadatos | +| `#94A3B8` | `slate-400` | Placeholders, texto muy secundario | +| `#E2E8F0` | `slate-200` | Bordes generales | +| `#F1F5F9` | `slate-100` | Separadores sutiles | +| `#F8FAFC` | `slate-50` | Fondo de la app, canvas BPMN | + +### 2.6 Colores que NO usar + +``` +❌ #572FA2 Morado primario de CONCILIA — marca hermana, no mezclar +❌ #CB1889 Magenta de CONCILIA +❌ azul shadcn por defecto (221.2 83.2% 53.3%) — reemplazado por InQ orange +``` + +--- + +## 3. Tipografía + +### 3.1 Familias + +```css +/* Primaria — web app y body de PDFs */ +font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; + +/* Mono — números en tablas, datos financieros */ +font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace; +``` + +Tailwind: `font-sans` / `font-mono` + +### 3.2 Escala PDF + +| Elemento | Tamaño | Peso | Tracking | +|---|---|---|---| +| Logo "InQ ROI" en header | 22px | 700 | −0.8px | +| Título de sección | 16px | 500 | normal | +| KPI Hero (cifra) | 30px | 700 | −1px | +| KPI secundario (cifra) | 16px | 700 | normal | +| Body text | 11px | 400 | normal | +| Labels en cards | 8px | 500 | 1px uppercase | +| Tabla header | 10px | 500 | normal | +| Tabla body | 10px | 400 | normal | +| Footer | 9px | 400 | normal | + +### 3.3 Escala Web App + +| Elemento | Tamaño | +|---|---| +| Logo header | 18px / 700 | +| Page title | 16px / 500 | +| KPI Hero | 28px / 700 | +| KPI secundario | 16px / 700 | +| Nav / Tabs | 12px / 400-500 | +| Body | 12-13px / 400 | +| Labels en panels | 10-11px / 400-500 | + +--- + +## 4. Componentes + +### 4.1 KPI Hero (gradiente naranja → magenta) + +``` +Fondo: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%) +Padding: 16-18px +Border-radius: 6-8px +Label: 9-10px / uppercase / letter-spacing 1.2px / white opacity 0.9 +Cifra: 28-30px / 700 / letter-spacing −1px / white +Subtítulo: 10-11px / white opacity 0.85 +``` + +Uso: el KPI "Ahorro proyectado a N años" — el más importante del reporte ROI. + +### 4.2 KPI Card (secundario, fondo naranja claro) + +``` +Fondo: #FEF3E2 (inq-orange-light) +Padding: 10px 12px +Border-radius: 6px +Label: 8px / 500 / letter-spacing 1px / color #92400E / uppercase +Cifra: 16px / 700 / color #0F172A +Delta: 10px / 500 / color #B45309 +``` + +### 4.3 Banner narrativo (resumen ejecutivo) + +``` +Fondo: #FFF8ED (inq-orange-lighter) +Border-left: 3px solid #F59845 +Padding: 10-12px 14px +Border-radius: 0 4px 4px 0 +Texto: 11px / 400 / line-height 1.55 / color #475569 +``` + +### 4.4 Sección Transparencia Metodológica + +``` +Fondo: #FFFBEB (warning-bg) +Border: 0.5px solid #F59E0B +Padding: 12px 14px +Border-radius: 6px +Título: 11px / 500 / color #92400E / con ícono ⚠ +Texto: 10px / 400 / line-height 1.6 / color #78350F +``` + +4 condiciones que activan la sección: +1. Actividades `automatable=true` con `automatedCostFixed=0` y `automatedTimeMinutes=0` +2. `automationInvestment=0` +3. `roiAnnualPercent > 1000` (finito) +4. (reservado para futuras reglas) + +### 4.5 Tabla comparativa PDF + +``` +Header row: + Fondo: #FFF8ED + Border-bottom: 1px solid #F59845 + Texto: 10px / 500 / #92400E + +Body row — automatizable: + Fondo: white + +Body row — no automatizable: + Fondo: #F8FAFC + Texto: color #64748B (más tenue) + +Total row: + Fondo: #FFF8ED + Border-top: 1.5px solid #F59845 + Texto: 10px / 500 / #0F172A +``` + +### 4.6 Header PDF + +``` +Layout: flex justify-between +Border-bottom: 3px solid #F59845 (pág. 1) / 2px (otras) +Padding-bottom: 10-12px +Margin-bottom: 14-16px + +Izquierda: + "InQ ROI" 18-22px / 700 / #F59845 + Tagline: 9px / letter-spacing 1.5px / #94A3B8 (solo pág. 1) + +Derecha: + "UN PRODUCTO DE" 9px / letter-spacing 1px / #94A3B8 + "InQ" 16px / 700 / #475569 + "InQuality" 9px / #64748B +``` + +### 4.7 Footer PDF + +``` +Position: absolute bottom 14-16mm +Padding-top: 6-8px +Border-top: 0.5px solid #E2E8F0 +Layout: flex justify-between +Font: 9px / 400 / #94A3B8 + +Izquierda: "InQ ROI" bold #F59845 " · Powered by InQuality · " cliente · fecha +Derecha: "Página X de Y" +``` + +### 4.8 Badge ⚡ (Automatizable) + +#### En canvas BPMN overlay +``` +Diámetro: 14px +Fondo: #F59845 (naranja sólido) +Border: 1.5px solid white +Posición: { top: -8, left: nodeWidth - 12 } +Símbolo: ⚡ blanco 8px +``` + +Nota: en Sprint 1 el badge usa fondo `#fffbeb` (ámbar-50) con ícono ámbar. La migración a naranja sólido se hace en **Etapa 9** de Sprint 1.5. + +#### En tablas y leyendas +``` +Diámetro: 14px inline +Fondo: #F59845 +Color: white +``` + +### 4.9 Layout híbrido de PDFs (portrait + landscape) + +Los PDFs combinan orientaciones por página: + +- **Páginas SIN diagrama**: A4 vertical (210×297mm) — texto, tablas, KPIs +- **Página DEL diagrama BPMN**: A4 horizontal (297×210mm) — para que el diagrama ocupe espacio real + +Implementación jsPDF: `doc.addPage([297, 210], 'landscape')` + +--- + +## 5. Tokens en código + +### Web (Tailwind) + +```tsx +// Colores de marca +
// #F59845 +
// #B45309 +
// #FEF3E2 +
// texto naranja +
// borde naranja + +// Gradiente identidad (como style prop — Tailwind no soporta gradientes dinámicos) +
+ +// Semánticos +
// #16A34A +
// #FFFBEB +``` + +### PDF (jsPDF) + +```typescript +// Constante en pdf-sections.ts (a migrar en Etapas 4-8) +const PDF_ORANGE: [number, number, number] = [245, 152, 69] // #F59845 +const PDF_ORANGE_LIGHT: [number, number, number] = [254, 243, 226] // #FEF3E2 +const PDF_MAGENTA: [number, number, number] = [237, 62, 143] // #ED3E8F + +// Gradiente en jsPDF se simula con pasos (ver pdf-sections-roi.ts) +``` + +--- + +## 6. Reglas de uso — DO / DON'T + +### DO ✅ +- Usar `bg-primary` / `text-primary` para todos los CTAs — hereda el naranja de `--primary` +- Usar gradiente identidad en exactamente 1 KPI Hero por página/vista +- Usar `font-mono` para todos los números financieros +- Escribir siempre **InQ** con I-n-Q + +### DON'T ❌ +- Usar `bg-blue-*` donde debería ir naranja InQ +- Aplicar el gradiente en más de un elemento por vista +- Usar colores de CONCILIA (`#572FA2`, `#CB1889`) +- Cambiar los colores del heatmap sin recalibrar los tests E2E + +--- + +*Actualizado: Sprint 1.5 Etapa 1 — 2026-05-16* diff --git a/TODO.md b/TODO.md index 41b812c..12081cb 100644 --- a/TODO.md +++ b/TODO.md @@ -31,6 +31,8 @@ - [ ] **Indicador visual en el reporte de actividades automatable** (borde punteado o ícono diferenciador): en Sprint 1 se usa solo leyenda de texto. Evaluar si el cliente necesita más claridad visual al comparar Actual vs Automatizado. +- [ ] **Sprint 3-4: revisar paleta del heatmap** (verde/ámbar/rojo saturados vs. pasteles). Los colores saturados actuales (`#10B981`, `#F59E0B`, `#EF4444`) funcionan bien en pantallas grandes de talleres. El brief de Sprint 1.5 propone pasteles más "consultivos" (`#BBF7D0`, `#FED7AA`, `#FECACA`), pero el cambio requiere recalibrar los tests E2E de análisis de píxeles (umbrales de verde/ámbar/rojo). Hacer con feedback real de uso en talleres InQuality. + - [ ] **Columna "Eficiencia de automatización" en ComparisonTable**: métrica = `(ahorro$ × probabilidad) / inversión-prorrateada`. Permite rankear actividades por "qué tan valiosa es automatizar cada una" en lugar de solo "cuánto cuestan". Útil en conversaciones de pre-venta donde el cliente quiere priorizar qué automatizar primero. ## Baja prioridad / Fase 2 diff --git a/etapa-1-audit.md b/etapa-1-audit.md new file mode 100644 index 0000000..9976909 --- /dev/null +++ b/etapa-1-audit.md @@ -0,0 +1,90 @@ +# Auditoría de colores — Etapa 1 Sprint 1.5 + +> Hallazgos del audit de azules, hardcodes y `primary` en el código fuente. +> **No se resuelven en Etapa 1.** Las acciones se ejecutan en Etapas 3 (Web App) y 4-8 (PDFs). +> +> Fecha: 2026-05-16 · Ejecutado por: Claude Code +> Comandos: `grep -rn "blue|sky|indigo|3B82F6|2563EB" src/` + `grep -rn "#[0-9a-fA-F]{6}" src/` + +--- + +## Categorías + +- **Migrar a InQ orange**: color azul que debería ser naranja de marca +- **Mantener azul funcional**: azul donde es convención semántica (info, links, paralelo AND) +- **Migrar a neutral**: azul accidental que debería ser slate/gray +- **Migrar a token**: hex hardcodeado que tiene un token equivalente en tailwind.config.js + +--- + +## Hallazgos — Azules en clases Tailwind + +| Archivo:línea | Clase actual | Categoría | Acción sugerida | +|---|---|---|---| +| `GatewayPanel.tsx:122` | `bg-blue-50 border-blue-200` | **Mantener azul funcional** | El azul en gateways AND paralelos es convención visual (flujo paralelo = azul). Evaluar en Sprint 2 si cambiar a slate-50 sin perder semántica. | +| `GatewayPanel.tsx:124` | `text-blue-500` | **Mantener azul funcional** | Ídem — ícono Info en bloque paralelo | +| `GatewayPanel.tsx:126-127` | `text-blue-800`, `text-blue-700` | **Mantener azul funcional** | Texto del bloque informativo de gateway AND | +| `GatewayPanel.tsx:144` | `text-blue-600` | **Mantener azul funcional** | "100%" en gateway paralelo — valor fijo, semántica coherente | +| `ResourcesPanel.tsx:22` | `bg-blue-100 text-blue-700` (rol "role") | **Migrar a neutral** | Badge de tipo "role" no tiene razón de ser azul. Migrar a slate o usar color propio del sistema de recursos. Etapa 3. | + +## Hallazgos — `PDF.blue` en exportación + +| Archivo:línea | Color actual | Categoría | Acción sugerida | +|---|---|---|---| +| `pdf-sections.ts:9` | `blue: [30, 64, 175]` (`#1E40AF`) | **Migrar a InQ orange** | Header de tabla PDF usa azul corporativo. Reemplazar por naranja InQ `[245, 152, 69]` (`#F59845`) en Etapa 4 (PDF: header y footer). | +| `pdf-sections.ts:112` | `PDF.blue` en KPI card accent | **Migrar a InQ orange** | El KPI "Costo total" usa azul como accent. Cambiar a naranja InQ en Etapa 6 (PDF: rediseño página 1). | +| `pdf-export.ts:120` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla de costos en azul. Migrar en Etapa 7 (PDF: páginas 3-4). | +| `pdf-sections-roi.ts:203` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla comparativa ROI. Migrar en Etapa 7. | + +## Hallazgos — Hex hardcodes en componentes React + +| Archivo:línea | Hex | Descripción | Categoría | Acción sugerida | +|---|---|---|---|---| +| `BpmnCanvas.tsx:24` | `#f59e0b` | Stroke del ícono Bot en SVG inline | **Migrar a InQ orange** | En Etapa 9 el badge ⚡ cambia a fondo naranja sólido `#F59845`. El stroke del SVG se rediseña en esa etapa. | +| `BpmnCanvas.tsx:40` | `#fffbeb` | Fondo del badge Bot (amber-50) | **Migrar a InQ orange** | Reemplazar por `var(--inq-orange-lighter)` `#FFF8ED` en Etapa 9. | +| `BpmnCanvas.tsx:41` | `#e2e8f0` | Borde del badge Bot | **Mantener neutral** | Borde sutil, está bien como slate-200. | +| `CumulativeSavingsChart.tsx:32,34` | `#10b981` | Color del marker de payback | **Migrar a token** | Verde éxito = `var(--color-success)` `#16A34A`. Migrar en Etapa 3. | +| `CumulativeSavingsChart.tsx:55` | `#10b981`, `#ef4444` | Colores del tooltip (positivo/negativo) | **Migrar a token** | Usar `--color-success` y `--color-danger`. Etapa 3. | +| `CumulativeSavingsChart.tsx:91,102` | `#3b82f6` | Línea y punto del chart acumulado | **Migrar a InQ orange** | La línea del gráfico de trayectoria debería ser naranja InQ `#F59845` para coherencia de marca. Etapa 3. | +| `HeatmapCanvas.tsx:118` | `#f8fafc` | Background del canvas | **Mantener neutral** | slate-50 es correcto para fondo del diagrama BPMN. | +| `TopSavingsChart.tsx:73,79` | `#10b981` | Barras y labels del chart | **Migrar a token** | Verde éxito correcto. Usar `--color-success` vía `style={{ color: 'var(--color-success)' }}`. Etapa 3. | +| `HeatmapLegend.tsx:24` | `#10b981`, `#f59e0b`, `#ef4444` | Gradiente de la leyenda del heatmap | **Migrar a token** | Usar constantes exportadas de `colors.ts` o tokens `heatmap.*`. Etapa 3. | +| `chart-options.ts:12` | `#3b82f6` (role) | Color del tipo de recurso "role" | **Migrar a neutral** | El azul para "roles" no es marca InQ. Evaluar paleta diferenciadora de tipos en Sprint 2. | +| `chart-options.ts:12` | `#8b5cf6` (system) | Color del tipo "system" | **Mantener azul funcional** | Violeta para sistemas es una convención razonable. Evaluar en Sprint 2. | +| `chart-options.ts:123` | `#3b82f6` | Costo directo en donut chart | **Migrar a InQ orange** | El donut de composición directo/overhead debería usar naranja InQ. Etapa 3. | +| `chart-options.ts:57,69,211,224` | `#f1f5f9`, `#e2e8f0` | Grid lines y ejes de charts | **Mantener neutral** | slate-100/200 son correctos para UI de soporte. | +| `chart-options.ts:63,107,209` | `#475569` | Labels de ejes | **Mantener neutral** | slate-600, correcto. | +| `chart-options.ts:78,217,237` | `#64748b`, `#94a3b8` | Labels secundarios | **Mantener neutral** | slate-500/400, correctos. | +| `chart-options.ts:136` | `#1e293b` | Fill del label de total en donut | **Mantener neutral** | slate-800, correcto para texto. | + +## Hallazgos — `primary` en JSX + +| Archivo | Usos | Evaluación | +|---|---|---| +| `router.tsx`, `WorkspacePage.tsx` | `text-primary` spinner | ✅ Correcto — spinner naranja InQ ahora | +| `ResourcesPanel.tsx:101` | `border-primary/20 bg-primary/5` | ✅ Correcto — borde/fondo naranja sutil | +| `RoiKpiBar.tsx:88-89` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono Calendar naranja | +| `KpiBar.tsx:46-47` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono DollarSign naranja | +| `ActivitiesTable.tsx:22-23` | `text-primary` arrows | ✅ Correcto — flechas de ordenamiento naranjas | +| `ActivitiesTable.tsx:96` | `bg-primary/5 ring-primary/20` | ✅ Correcto — highlight de fila naranja | +| `ImportPage.tsx:173,198-199,205,210-211,252,255-258` | `text-primary`, `bg-primary/*`, `border-primary` | ✅ Correcto — AccentS de la landing page naranjas | +| `SampleProcessLoader.tsx:77,83-84,92` | `hover:border-primary/30`, `bg-primary/10`, `text-primary` | ✅ Correcto | +| `WorkspacePage.tsx:178,243` | `text-primary border-primary/30`, `bg-primary` | ✅ Correcto | +| `slider.tsx` | `bg-primary/20`, `bg-primary`, `border-primary/50` | ✅ Correcto — slider naranja | +| `tooltip.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — tooltip naranja | +| `switch.tsx` | `bg-primary` when checked | ✅ Correcto — switch naranja | +| `button.tsx` | `bg-primary text-primary-foreground` default | ✅ Correcto — botón naranja | +| `badge.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — badge naranja | + +--- + +## Resumen de acciones pendientes + +| Etapa | Archivos afectados | Acción | +|---|---|---| +| Etapa 3 (Web App) | `CumulativeSavingsChart.tsx`, `TopSavingsChart.tsx`, `HeatmapLegend.tsx`, `chart-options.ts` | Migrar hex a tokens CSS/constantes | +| Etapa 4-8 (PDFs) | `pdf-sections.ts`, `pdf-export.ts`, `pdf-sections-roi.ts` | Reemplazar `PDF.blue` por array naranja InQ | +| Etapa 9 (Badge ⚡) | `BpmnCanvas.tsx` | Rediseño completo del badge a naranja sólido | +| Sprint 2 | `ResourcesPanel.tsx`, `GatewayPanel.tsx`, `chart-options.ts` | Evaluar paleta de tipos de recurso y gateways | + +**No se toca nada de lo anterior en Etapa 1.** diff --git a/sprints/sprint-1-5/ETAPA_2_PROMPT.md b/sprints/sprint-1-5/ETAPA_2_PROMPT.md new file mode 100644 index 0000000..e69de29 diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx index c99280c..7d94059 100644 --- a/src/components/ui/tabs.tsx +++ b/src/components/ui/tabs.tsx @@ -26,7 +26,7 @@ const TabsTrigger = React.forwardRef< + +describe('Design tokens — paleta InQ ROI', () => { + it('expone tokens de marca InQ con estructura anidada correcta', () => { + const inq = colors.inq + + expect(inq.orange.DEFAULT).toBe('#F59845') + expect(inq.orange.dark).toBe('#B45309') + expect(inq.orange.light).toBe('#FEF3E2') + expect(inq.orange.lighter).toBe('#FFF8ED') + expect(inq.magenta).toBe('#ED3E8F') + }) + + it('NO incluye los colores de CONCILIA (marca hermana, no mezclar)', () => { + const configStr = JSON.stringify(tailwindConfig) + + // Morado primario de CONCILIA + expect(configStr).not.toContain('#572FA2') + expect(configStr).not.toContain('#572fa2') + + // Magenta de CONCILIA + expect(configStr).not.toContain('#CB1889') + expect(configStr).not.toContain('#cb1889') + }) + + it('expone tokens del heatmap saturado (calibrado para tests E2E)', () => { + const heatmap = colors.heatmap + + // Valores en mayúscula: #10B981, #F59E0B, #EF4444 + // Deben coincidir con HEATMAP_LOW/MID/HIGH en src/lib/colors.ts + expect(heatmap.low).toBe('#10B981') + expect(heatmap.mid).toBe('#F59E0B') + expect(heatmap.high).toBe('#EF4444') + }) +}) diff --git a/tests/e2e/screenshots-etapa-1.spec.ts b/tests/e2e/screenshots-etapa-1.spec.ts new file mode 100644 index 0000000..6208f0d --- /dev/null +++ b/tests/e2e/screenshots-etapa-1.spec.ts @@ -0,0 +1,65 @@ +/** + * Screenshots de validación visual — Etapa 1 Sprint 1.5. + * + * Captura 3 vistas que muestran la identidad InQ aplicada: + * 1. workspace.png — CTAs naranjas, Simular button, tabs + * 2. report-tabs.png — tab activo naranja en el reporte + * 3. switch-on.png — switch de automatización en estado ON naranja + * + * Estos screenshots son evidencia de que el cambio de --primary a naranja + * se ve correctamente en la aplicación real. + */ +import { test } from '@playwright/test' +import { resolve } from 'path' +import { mkdirSync } from 'fs' +import { fileURLToPath } from 'url' + +const __dirname = fileURLToPath(new URL('.', import.meta.url)) +const BPMN_DIR = resolve(__dirname, '../../public/sample-processes') +const OUT_DIR = resolve(__dirname, '../screenshots/etapa-1') + +test.beforeAll(() => { mkdirSync(OUT_DIR, { recursive: true }) }) + +test('screenshot workspace — CTAs naranjas visibles', async ({ page }) => { + await page.goto('/') + await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn')) + await page.waitForURL(/\/workspace\//, { timeout: 15_000 }) + await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 }) + await page.waitForTimeout(1_000) + + await page.screenshot({ path: resolve(OUT_DIR, 'workspace.png'), fullPage: false }) +}) + +test('screenshot switch ON — switch de automatización naranja', async ({ page }) => { + await page.goto('/') + await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn')) + await page.waitForURL(/\/workspace\//, { timeout: 15_000 }) + await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 }) + await page.waitForTimeout(1_500) + + // Hacer click en el primer task del BPMN para abrir el ActivityPanel + await page.locator('[data-element-id="task1"]').first().click() + await page.waitForTimeout(500) + + // Encender el switch de automatización + const toggle = page.getByRole('switch', { name: /automatizable/i }) + await toggle.click() + await page.waitForTimeout(300) + + await page.screenshot({ path: resolve(OUT_DIR, 'switch-on.png'), fullPage: false }) +}) + +test('screenshot report-tabs — tab activo naranja', async ({ page }) => { + await page.goto('/') + await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'medium-with-gateways.bpmn')) + await page.waitForURL(/\/workspace\//, { timeout: 15_000 }) + await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 }) + await page.waitForTimeout(1_500) + + const simBtn = page.getByRole('button', { name: 'Simular' }) + await simBtn.click() + await page.waitForURL(/\/report\//, { timeout: 20_000 }) + await page.waitForSelector('button:has-text("Exportar PDF")', { timeout: 20_000 }) + + await page.screenshot({ path: resolve(OUT_DIR, 'report-tabs.png'), fullPage: false }) +}) diff --git a/tests/lib/format-payback.test.ts b/tests/lib/format-payback.test.ts new file mode 100644 index 0000000..0ad5e5d --- /dev/null +++ b/tests/lib/format-payback.test.ts @@ -0,0 +1,21 @@ +/** + * Tests de formatPayback — Sprint 1.5 Etapa 2. + * + * Stubs preparados. La implementación se agrega en Etapa 2. + * Los 7 casos están definidos en SPRINT_1_5_BRIEF_REDISENIO_VISUAL.md § 3.4. + * + * Regla: un payback de "0.0 meses" (como mostraba el sistema con costos + * artificialmente bajos) es confuso. formatPayback resuelve esto con + * una escala legible para el consultor y el cliente. + */ +import { describe, it } from 'vitest' + +describe('formatPayback', () => { + it.todo('0 → "Inmediato" (inversión cero con ahorro positivo)') + it.todo('0.05 → "< 1 día" (payback de horas, prácticamente instantáneo)') + it.todo('0.5 → "< 1 mes (0.50 meses)"') + it.todo('6 → "6.0 meses"') + it.todo('15 → "15.0 meses (~1.3 años)"') + it.todo('30 → "2.5 años"') + it.todo('Infinity → "No recupera en horizonte"') +}) diff --git a/tests/screenshots/etapa-1/report-tabs.png b/tests/screenshots/etapa-1/report-tabs.png new file mode 100644 index 0000000..54b6806 Binary files /dev/null and b/tests/screenshots/etapa-1/report-tabs.png differ diff --git a/tests/screenshots/etapa-1/switch-on.png b/tests/screenshots/etapa-1/switch-on.png new file mode 100644 index 0000000..eeb9f01 Binary files /dev/null and b/tests/screenshots/etapa-1/switch-on.png differ diff --git a/tests/screenshots/etapa-1/workspace.png b/tests/screenshots/etapa-1/workspace.png new file mode 100644 index 0000000..2b294ca Binary files /dev/null and b/tests/screenshots/etapa-1/workspace.png differ