- Actualizar ModalAsignacionRapida a sintaxis correcta de Nuxt UI v4
- Usar v-model:open en lugar de v-model
- Usar slots #body y #footer directamente
- Eliminar UCard (deprecado)
- Aplicar clases cata-* para mantener consistencia con el resto de la app
- Usar cata-text para textos
- Usar cata-button para botones
- Usar cata-input para inputs
- Usar cata-outline-box para bordes
- Respetar colores personalizados del usuario mediante variables CSS
- selected-category usa var(--cata-primary)
- Soporte para modo oscuro con efectos de sombra
- Eliminar icono de estrella/rayo del BotonNubeCaustica
- Simplificar diseño dejando solo la nube con patrones cáusticos
- Eliminar animación sparkle asociada
- Integrar modal correctamente en FormularioMuestra
- Mover botón dentro del slot por defecto del modal
- Eliminar modal duplicado del template
- Crear ModalAsignacionRapida.vue con lógica de distribución por múltiplos de 8
- Input numérico (8-80) para puntaje total deseado
- Cálculo automático del múltiplo de 8 más cercano
- Si múltiplo < valor: permite seleccionar categorías que sobresalen (+1)
- Si múltiplo > valor: permite seleccionar categorías que palidecen (-1)
- Si múltiplo = valor: asignación directa sin ajustes
- Crear BotonNubeCaustica.vue con diseño especial
- Forma de nube usando SVG path
- Animación de patrones de luz cáustica con gradientes animados
- Efectos de brillo y ondas al hacer hover
- Icono de rayo mágico con animación sparkle
- Integrar funcionalidad en FormularioMuestra.vue
- Ubicar botón en esquina superior izquierda de sección Descriptiva/Afectiva
- Aplicar puntajes calculados a todas las categorías descriptivas
- Actualizar puntaje final automáticamente
- Corregir comentario: "Suma de valores descriptivos" (era "afectivos")
- Modificar calcularPuntajeFinal para sumar intensidades descriptivas
en lugar de afectivas
- Actualizar comentarios JSDoc para reflejar el cambio
- El puntaje final ahora refleja correctamente la suma de todas las
puntuaciones descriptivas (1-10) de cada categoría
- Evitar deselección al presionar el mismo corazón/círculo ya seleccionado
- Cambiar iconos de corazón de Lucide a Heroicons para mejor distinción visual
- No seleccionado: i-heroicons-heart (outline)
- Seleccionado: i-heroicons-heart-solid (relleno)
- Eliminar clase CSS icono-filled innecesaria
- Crear subcategorías dinámicas basadas en las muestras de la sesión
- Los filtros en Impresión Global ahora controlan qué muestras se muestran
- Filtrar accordionItems según subcategorías activas en impresion-global
- Cada muestra aparece como opción de filtro con su nombre o "Muestra #"
- Incluir selector de Sensación en la Boca en la sección Organoléptica de Impresión Global
- Incluir selector de Gustos Predominantes en la sección Organoléptica de Impresión Global
- Mantener la misma funcionalidad y estilos que en la tab Organoléptica
- Reducir tamaño de iconos de 1.5rem a 1rem en SelectorIntensidad
- Reducir espaciado entre iconos y padding del contenedor
- Cambiar gap de grids de sliders de 4 a 2
- Implementar filtrado restrictivo por tipo (descriptiva/afectiva) y categoría
- Agregar computed properties individuales para cada slider
- Cuando se selecciona "Afectiva" + "Sensación en la Boca", solo se muestra ese slider específico
- Eliminar grid en desktop para categorías principales de SelectorFamilia
- Usar flex-wrap en todos los tamaños de pantalla (igual que subcategorías)
- Mantener solo incremento de min-height en desktop (40px vs 32px)
- Resultado: categorías ahora fluyen en una sola fila con wrap cuando es necesario
CAMBIOS EN SENSACIONES EN BOCA:
- Reducir opciones a solo 5: Áspero, Aceitoso, Metálico, Deja seca la boca, Suave
- Cambiar de selección múltiple a selección única
- Actualizar tipo de sensacionEnBoca: SensacionBoca[] → SensacionBoca | null
CAMBIOS EN CHECKBOXES (sensaciones y gustos):
- Hacer checkboxes tan compactos como subcategorías de SelectorFamilia
- Usar flex-wrap en todos los breakpoints (eliminar grid en desktop)
- Dimensiones ultra compactas:
* Desktop: min-height 32px, padding 0.375rem 0.5rem, font-size 0.75rem
* Mobile: min-height 28px, padding 0.25rem 0.375rem, font-size 0.6875rem
* Touch: min-height 36px para dispositivos táctiles
ARCHIVOS MODIFICADOS:
- app/types/catacion.ts: Actualizar SensacionBoca y SENSACIONES_BOCA
- app/composables/useCatacion.ts: Cambiar actualizarSensacionBoca a selección única
- app/components/cata/FormularioMuestra.vue: UI compacta y selección única
- app/components/cata/ResumenMuestra.vue: Adaptar a sensacionEnBoca única
- Cambiar layout de grid fijo a flex-wrap en mobile para sensaciones y gustos
- Mantener grid responsive en desktop (3 columnas para sensaciones, 5 para gustos)
- Reducir significativamente todas las dimensiones para mayor compactación:
* Desktop: min-height 36px, padding 0.375rem 0.5rem
* Mobile: min-height 28px, padding 0.25rem 0.375rem
* Font-size: 0.75rem desktop, 0.6875rem mobile
- Agregar animaciones y estados focus consistentes
- Touch-friendly en dispositivos táctiles (36px min-height)
- Cambiar de type='multiple' a type='single' (solo un item abierto a la vez)
- Todos los accordions pueden estar cerrados (collapsible: true por defecto)
- Actualizar estado accordionAbierto de string[] a string | undefined
- Actualizar lógica toggleCollapseAll para modo single
- Agregar border-t al content del accordion para mejor separación visual
- Actualizar títulos del botón flotante: 'Abrir primera muestra' / 'Cerrar muestra abierta'
- Alinear puntaje final a la derecha en ResumenMuestra (ml-auto)
- Cambiar estilo de accordion: underline simple sin gap entre items
- Ajustar ancho 100% en móviles sin padding lateral (px-0 sm:px-4)
- Eliminar headers redundantes en tabs específicas:
* Organoléptica: eliminar 'Características Organolépticas'
* Descriptiva/Afectiva: eliminar 'Intensidades Descriptivas y Afectivas'
* Defectos: eliminar 'Defectos y Uniformidad'
- Mantener headers en tab Impresión Global para mejor navegación
- Agregar función getCategoryIcon() en FormularioMuestra y ResumenMuestra
- Iconos Lucide para cada categoría:
* fragancia: flower-2, aroma: wind, sabor: candy
* saborResidual: timer, acidez: citrus, dulzor: cookie
* sensacionBoca: droplets, impresionGlobal: star
- Actualizar todos los títulos de sección con iconos
- Modificar chips de ResumenMuestra para mostrar solo icono + valor descriptivo
- Eliminar valores afectivos y emojis de chips
- Agregar estilos CSS para .chip-icon
- Agregar prop tabActiva a ResumenMuestra.vue
- Implementar computed properties para filtrado:
* mostrarChipsOrganolepticos (organoleptica + impresion-global)
* mostrarChipsIntensidades (descriptiva-afectiva + impresion-global)
* mostrarChipsDefectos (defectos + impresion-global)
- Envolver grupos de chips con template v-if según filtrado
- Pasar prop :tab-activa desde sesion.vue a ResumenMuestra
- En impresion-global se muestran TODOS los chips
- En otras tabs solo chips pertinentes a esa categoría
- Reducir font-size de chips de 0.75rem a 0.625rem (0.5625rem en mobile)
- Reducir padding de chips de 0.25/0.5rem a 0.15/0.35rem
- Reducir gaps: entre chips de 1rem a 0.5rem, en línea de 2rem a 1.5rem
- Reducir tamaño de puntaje final y nombre de muestra
- Abreviar todas las etiquetas de chips:
* F/A (Fragancia/Aroma), Sab (Sabor), Gus (Gustos), Sen (Sensación)
* Fra, Aro, Sb, S.R (Sabor Residual), Aci, Dul, Sn, Imp
* NoUnif (No Uniformes), Defec (Defectuosas)
- Eliminar espacios en arrays join (coma sin espacio)
- Optimizar responsive para mobile aún más compacto
- Cambiar 'cuerpo' por 'sensacionBoca' (propiedad correcta del tipo)
- Cambiar 'balance' por 'impresionGlobal' (propiedad correcta del tipo)
- Las propiedades ahora coinciden con la interfaz Intensidades definida en catacion.ts
- Agregar puntaje final con badge color-coded según rangos
- Agregar chips para categorías organolépticas (fragancia/aroma, sabor, gustos, sensación)
- Agregar chips para todos los valores de intensidad (afectiva ❤️ y descriptiva 📊)
- Agregar chips condicionales para tazas no uniformes (warning)
- Agregar chips condicionales para tazas defectuosas con tipo de defecto (error)
- Layout de dos líneas: header con #/nombre/puntaje y chips informativos
- Diseño compacto y responsive
Limpia la UI del selector de intensidad para una experiencia más minimalista:
- Eliminado atributo title que mostraba tooltips con el valor
- Eliminada sección completa de indicadores numéricos (min/valor/max)
- El componente ahora solo muestra los iconos interactivos
- Mantiene toda la funcionalidad (selección, hover, deselección)
La interfaz es ahora más limpia y el usuario puede confiar en el feedback visual de los iconos activos para conocer el valor seleccionado.
Crea nuevo componente SelectorIntensidad que reemplaza los sliders tradicionales por un selector tipo "rating" con iconos clicables:
Características del nuevo componente:
- Usa círculos (circle/circle-dot) para intensidad descriptiva
- Usa corazones (heart) para intensidad afectiva
- Los iconos se llenan hasta el valor seleccionado
- Efecto hover para preview
- Mismo rango: descriptiva (1-10), afectiva (1-15)
- Click en mismo valor lo deselecciona (vuelve a null)
- Soporte para colores personalizados
- Efectos de glow en modo oscuro
- Responsive (iconos más pequeños en móvil)
Cambios técnicos:
- Nuevo archivo: app/components/cata/SelectorIntensidad.vue
- Modificado: app/components/cata/FormularioMuestra.vue
- Reemplazado CataSliderIntensidad por CataSelectorIntensidad (global)
- Mantiene la misma interfaz de props y eventos que SliderIntensidad
Implementa la funcionalidad para que las subcategorías seleccionadas persistan:
- Entre cambios de tabs (cada tab mantiene sus propias subcategorías)
- Entre refrescos de página (guardado en localStorage)
Cambios técnicos:
- Modificado useCatacion.ts para guardar subcategorías por tab en lugar de array global
- Agregada función actualizarSubcategorias() que persiste en localStorage
- subcategoriasActivas ahora es computed basado en la tab activa
- Removida limpieza de subcategorías al cambiar de tab en sesion.vue
- Actualizado toggleSubcategoria para usar la nueva función de persistencia
- Mover sección Sensaciones en Boca de Impresión Global a Organoléptica
- Mover sección Gustos Predominantes de Impresión Global a Organoléptica
- Agregar v-if mostrarSensacionBocaOrganoleptica para filtrado por subcategoría
- Agregar v-if mostrarGustosPredominantes para filtrado por subcategoría
- Renombrar Detalles Adicionales a Notas Adicionales en Impresión Global
- Cambiar subcategoriaActiva a subcategoriasActivas (array) para permitir selección múltiple
- Agregar flex-wrap a barra de subcategorías en lugar de scroll horizontal
- Implementar toggleSubcategoria para agregar/quitar subcategorías
- Pasar subcategoriasActivas a FormularioMuestra como prop
- Agregar helpers deberMostrarSeccion para filtrar inputs
- Aplicar v-if a todas las secciones según subcategorías activas
- Botón Limpiar Todo para resetear filtros
- No activar cargando.value durante actualizar() en useIndexedDB
- Evitar que el loading spinner desmonte todo el formulario al guardar
- Mantener UI fluida durante actualizaciones en tiempo real
- Usar toRaw() + JSON.parse/stringify para deep clone sin Proxies
- No modificar modificadoEn en objeto reactivo, solo en copia
- Evitar re-renderizados innecesarios manteniendo referencias estables
- Reducir padding del botón de p-3 a p-2 (más compacto)
- Reducir tamaño del icono de w-6 h-6 a w-5 h-5
- Agregar flex items-center justify-center para centrar el icono
- Eliminar shadow con glow de color
- Usar fondo sólido con var(--cata-bg) en lugar de transparente
- Aplicar sombra simple con rgba (sin color del tema)
- Eliminar ajustes responsive de padding innecesarios
- Mejorar z-index para que se sobreponga correctamente a elementos
- Agregar clonación en saveSession() y updateSession()
- Mantener mutaciones directas en el estado reactivo
- Resolver error DataCloneError al guardar objetos reactivos en IndexedDB
- Modificar useIndexedDB para no reemplazar sesionActiva en actualizar()
- Modificar useCatacion para mutar directamente las propiedades
- Eliminar todas las clonaciones con JSON.parse/stringify
- Mantener referencias de objetos estables para Vue reactivity
- Mover botón Finalizar Sesión del flotante al header
- Cambiar botón flotante para colapsar/expandir todos los acordiones
- Agregar opción Finalizar Sesión al menú desplegable móvil
- Implementar función toggleCollapseAll para control de acordiones
- Agregar computed todosColapsados para estado de acordiones
- Usar iconos maximize-2/minimize-2 según estado
- Hacer botón flotante circular para mejor identificación
- Arreglar hover de acordiones para usar color personalizado
- Agregar estilos :deep() para .accordion-trigger:hover
- Usar color-mix con var(--cata-primary) en hover
- Aplicar 5% opacidad en modo claro, 10% en modo oscuro
- Remover JSON.parse(JSON.stringify()) de accordionItems computed
- Remover clonación innecesaria en obtenerMuestraPorValue
- Pasar referencias directas en lugar de copias profundas
- Los accordiones ahora mantienen su estado sin parpadeos
- Mejora significativa en la fluidez de la interfaz
El problema era que al clonar las muestras en cada render, Vue detectaba
objetos "nuevos" y re-montaba completamente los componentes accordion,
causando un efecto visual de parpadeo cada vez que se actualizaba un valor.
- Agregar validación completa en loadCustomColors para detectar formato incompatible
- Proteger setCustomColors asegurando que la estructura existe antes de asignar
- Validar estructura en getCurrentColors y retornar defaults si no existe
- Validar estructura en hasCustomColors y retornar false si no existe
- Validar estructura en inicializar antes de aplicar colores
- Limpiar localStorage automáticamente si detecta formato antiguo o corrupto
Soluciona error: TypeError Cannot create property 'primary' on string
cuando localStorage contiene datos de versión anterior
- Modificar useColorCustomization para manejar tres colores (primary, foreground, background)
- Actualizar interfaz ThemeColors con los tres colores
- Agregar selectores de color para fuente y fondo en el modal
- Implementar vista previa con los tres colores aplicados
- Actualizar funciones setCustomColors y resetColors para manejar múltiples colores
- Mantener almacenamiento separado por tema (light/dark)
- Aplicar colores a variables --cata-fg y --cata-bg además de --cata-primary
- Agregar composable useCategoryColors con 8 colores coordinados (light/dark)
- Colores por categoría: Fragancia (lavanda), Aroma (verde menta), Sabor (rojo),
Sabor Residual (naranja), Acidez (amarillo), Dulzor (rosa), Sensación en Boca (azul),
Impresión Global (turquesa)
- Eliminar hints de texto de SliderIntensidad (showDescription = false por defecto)
- Aplicar colores dinámicos a headers y sliders de cada categoría
- Aumentar font-weight de headers a 700 (bold)
- Los colores se adaptan automáticamente al tema light/dark
- Aplicar colores en formato HEX (no HSL sin prefijo)
- Solo modificar variables existentes (--cata-primary, --cata-primary-light, --cata-primary-dark)
- Eliminar sobrescritura de variables inexistentes (--cata-border, --cata-muted)
- Solo aplicar colores si hay personalización guardada (no sobrescribir por defecto)
- Limpiar variables CSS al resetear en lugar de aplicar colores por defecto
- Agregar función hslToHex para conversión correcta de colores
- Restaurar funcionamiento de bordes y efectos hover
- Mover trigger button al slot default de UModal
- Usar props title y description directamente en UModal
- Usar slots #body y #footer para el contenido del modal
- Mantener v-model:open para control de estado
- Eliminar wrapper div duplicado
- Seguir estructura correcta de Nuxt UI v4
- Crear composable useColorCustomization para manejar colores personalizados
- Agregar botón de paleta en CataUserInfo para acceder al color picker
- Implementar modal con selector de color (input color + text)
- Guardar preferencias en localStorage por tema (light/dark)
- Generar paleta de gradientes automáticamente desde color base
- Aplicar colores dinámicamente a variables CSS
- Incluir vista previa del color en el modal
- Botón para restablecer al color por defecto
- Persistencia de colores entre sesiones
- Inicialización automática en app.vue
- **Nuevas tabs reorganizadas:**
- Organoléptica: Selectores de familia de fragancia-aroma y sabor
- Descriptiva/Afectiva: Todos los sliders de intensidad (incluye impresión global)
- Defectos: Tazas no uniformes, defectuosas y tipo de defecto
- Impresión Global: Vista completa con todos los componentes
- **Selector de categorías mejorado:**
- Permitir selección múltiple de categorías padre
- Las subcategorías son la unión de las subcategorías de los padres seleccionados
- Permitir selección múltiple de subcategorías
- Actualizar resumen visual de selección
- **Tipos actualizados:**
- NotaSeleccionada ahora usa arrays para categorias y subcategorias
- TabCatacion actualizado con las nuevas tabs
- Funciones de actualización modificadas para trabajar con arrays
- **Correcciones TypeScript:**
- Usar JSON.parse(JSON.stringify()) para crear copias mutables de arrays readonly
- Resolver incompatibilidades de tipos entre readonly y mutable arrays
- Agregar clases flex items-center justify-center al botón de descarga
- Cambiar hidden sm:block por hidden sm:flex (coherente con flex)
- Ahora el botón tiene el mismo tamaño que los demás
- Archivo: app/pages/cata/sesion.vue:48
- Cambiar de slot #body a #content
- Agregar debug para ver qué contiene item cuando no tiene muestra
- Esto ayudará a entender qué datos recibe el slot
PROBLEMA: Toasts usaban estilos por defecto de Nuxt UI que no se acoplaban al diseño outline/terminal
SOLUCIÓN:
- Cambiar app.config.ts para usar clases CSS personalizadas en lugar de sintaxis arbitraria de Tailwind
- Agregar estilos CSS completos en main.css usando variables del sistema (--cata-bg, --cata-fg, --cata-primary)
- Implementar todas las variantes (primary, success, error, warning, info, neutral)
ESTILOS APLICADOS:
- Fondo: var(--cata-bg) en claro, negro 95% opaco en oscuro
- Bordes: outline usando var(--cata-primary) con opacidades
- Texto: fuente monospace en modo oscuro con text-shadow
- Iconos: colores específicos por tipo con drop-shadow en oscuro
- Efectos glow: sombras sutiles en modo oscuro según tipo
- IMPORTANTE: Usar !important para sobrescribir estilos de Nuxt UI