All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
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
1067 lines
41 KiB
Vue
1067 lines
41 KiB
Vue
<template>
|
||
<div class="formulario-muestra p-4 space-y-6">
|
||
<!-- Tab 1: Organoléptica (solo selectores de familia) -->
|
||
<div v-if="tabActiva === 'organoleptica'" class="tab-content cata-fade-in">
|
||
<!-- Selector de Familia de Fragancia/Aroma -->
|
||
<div v-if="mostrarFraganciaAroma" class="form-section">
|
||
<CataSelectorFamilia
|
||
tipo="fragancia-aroma"
|
||
label="Familia de Fragancia y Aroma"
|
||
:model-value="muestra.fraganciaAromaNotas"
|
||
@update:model-value="actualizarFraganciaAroma"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Selector de Familia de Sabor -->
|
||
<div v-if="mostrarSaborOrganoleptica" class="form-section">
|
||
<CataSelectorFamilia
|
||
tipo="sabor"
|
||
label="Familia de Sabor"
|
||
:model-value="muestra.saborNotas"
|
||
@update:model-value="actualizarSabor"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Sensaciones en Boca (selección única) -->
|
||
<div v-if="mostrarSensacionBocaOrganoleptica" class="form-section">
|
||
<label class="block text-sm font-medium mb-2 cata-text">
|
||
Sensación en la Boca
|
||
</label>
|
||
<div class="sensaciones-grid">
|
||
<button
|
||
v-for="sensacion in sensacionesBoca"
|
||
:key="sensacion"
|
||
type="button"
|
||
:class="[
|
||
'sensacion-item',
|
||
'cata-checkbox',
|
||
{ 'cata-checkbox-checked': muestra.sensacionEnBoca === sensacion },
|
||
]"
|
||
@click="seleccionarSensacionBoca(sensacion)"
|
||
>
|
||
<span class="sensacion-text cata-text">{{ sensacion }}</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Gustos Predominantes (máx 2) -->
|
||
<div v-if="mostrarGustosPredominantes" class="form-section">
|
||
<label class="block text-sm font-medium mb-2 cata-text">
|
||
Gustos Predominantes (mín 1, máx 2)
|
||
</label>
|
||
<div class="gustos-grid">
|
||
<button
|
||
v-for="gusto in gustosPredominantes"
|
||
:key="gusto"
|
||
type="button"
|
||
:class="[
|
||
'gusto-item',
|
||
'cata-checkbox',
|
||
{ 'cata-checkbox-checked': muestra.gustosPredominantes.includes(gusto) },
|
||
]"
|
||
:disabled="!muestra.gustosPredominantes.includes(gusto) && muestra.gustosPredominantes.length >= 2"
|
||
@click="toggleGustoPredominante(gusto)"
|
||
>
|
||
<span class="gusto-text cata-text">{{ gusto }}</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab 2: Descriptiva/Afectiva (todos los sliders incluyendo impresión global) -->
|
||
<div v-if="tabActiva === 'descriptiva-afectiva'" class="tab-content cata-fade-in">
|
||
<!-- Sliders de Fragancia -->
|
||
<div v-if="mostrarFraganciaSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('fragancia') }">
|
||
<UIcon :name="getCategoryIcon('fragancia')" class="w-5 h-5" />
|
||
Fragancia
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('fragancia'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.fragancia.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('fragancia'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.fragancia.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.fragancia.descriptiva"
|
||
:color="getCategoryColor('fragancia')"
|
||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.fragancia.afectiva"
|
||
:color="getCategoryColor('fragancia')"
|
||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Aroma -->
|
||
<div v-if="mostrarAromaSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('aroma') }">
|
||
<UIcon :name="getCategoryIcon('aroma')" class="w-5 h-5" />
|
||
Aroma
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('aroma'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.aroma.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('aroma'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.aroma.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.aroma.descriptiva"
|
||
:color="getCategoryColor('aroma')"
|
||
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.aroma.afectiva"
|
||
:color="getCategoryColor('aroma')"
|
||
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Sabor -->
|
||
<div v-if="mostrarSaborSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('sabor') }">
|
||
<UIcon :name="getCategoryIcon('sabor')" class="w-5 h-5" />
|
||
Sabor
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sabor'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.sabor.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sabor'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.sabor.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.sabor.descriptiva"
|
||
:color="getCategoryColor('sabor')"
|
||
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.sabor.afectiva"
|
||
:color="getCategoryColor('sabor')"
|
||
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Sabor Residual -->
|
||
<div v-if="mostrarSaborResidualSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('saborResidual') }">
|
||
<UIcon :name="getCategoryIcon('saborResidual')" class="w-5 h-5" />
|
||
Sabor Residual
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('saborResidual'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.saborResidual.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('saborResidual'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.saborResidual.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
||
:color="getCategoryColor('saborResidual')"
|
||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.saborResidual.afectiva"
|
||
:color="getCategoryColor('saborResidual')"
|
||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Acidez -->
|
||
<div v-if="mostrarAcidezSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('acidez') }">
|
||
<UIcon :name="getCategoryIcon('acidez')" class="w-5 h-5" />
|
||
Acidez
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('acidez'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.acidez.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('acidez'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.acidez.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.acidez.descriptiva"
|
||
:color="getCategoryColor('acidez')"
|
||
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.acidez.afectiva"
|
||
:color="getCategoryColor('acidez')"
|
||
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Dulzor -->
|
||
<div v-if="mostrarDulzorSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('dulzor') }">
|
||
<UIcon :name="getCategoryIcon('dulzor')" class="w-5 h-5" />
|
||
Dulzor
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('dulzor'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.dulzor.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('dulzor'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.dulzor.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.dulzor.descriptiva"
|
||
:color="getCategoryColor('dulzor')"
|
||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.dulzor.afectiva"
|
||
:color="getCategoryColor('dulzor')"
|
||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Sensación en Boca -->
|
||
<div v-if="mostrarSensacionBocaSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('sensacionBoca') }">
|
||
<UIcon :name="getCategoryIcon('sensacionBoca')" class="w-5 h-5" />
|
||
Sensación en la Boca
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sensacionBoca'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.sensacionBoca.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sensacionBoca'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.sensacionBoca.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
||
:color="getCategoryColor('sensacionBoca')"
|
||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
||
:color="getCategoryColor('sensacionBoca')"
|
||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sliders de Impresión Global -->
|
||
<div v-if="mostrarImpresionGlobalSlider" class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h5 class="form-section-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('impresionGlobal') }">
|
||
<UIcon :name="getCategoryIcon('impresionGlobal')" class="w-5 h-5" />
|
||
Impresión Global
|
||
</h5>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('impresionGlobal'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.impresionGlobal.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('impresionGlobal'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.impresionGlobal.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
||
:color="getCategoryColor('impresionGlobal')"
|
||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
||
:color="getCategoryColor('impresionGlobal')"
|
||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab 3: Defectos (tazas y defectos) -->
|
||
<div v-if="tabActiva === 'defectos'" class="tab-content cata-fade-in">
|
||
<!-- Tazas No Uniformes -->
|
||
<div class="form-section">
|
||
<CataSelectorTazas
|
||
tipo="uniformes"
|
||
label="Tazas NO Uniformes"
|
||
:model-value="muestra.tazasNoUniformes"
|
||
@update:model-value="actualizarTazasNoUniformes"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Tazas Defectuosas -->
|
||
<div class="form-section">
|
||
<CataSelectorTazas
|
||
tipo="defectuosas"
|
||
label="Tazas Defectuosas"
|
||
:model-value="muestra.tazasDefectuosas"
|
||
@update:model-value="actualizarTazasDefectuosas"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Tipo de Defecto -->
|
||
<div v-if="muestra.tazasDefectuosas.length > 0" class="form-section">
|
||
<label class="block text-sm font-medium mb-2 cata-text">
|
||
Tipo de Defecto
|
||
</label>
|
||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
||
<button
|
||
v-for="tipo in tiposDefectos"
|
||
:key="tipo || 'ninguno'"
|
||
type="button"
|
||
:class="[
|
||
'cata-checkbox',
|
||
{ 'cata-checkbox-checked': muestra.defecto === tipo },
|
||
]"
|
||
@click="actualizarDefecto(tipo)"
|
||
>
|
||
<span class="cata-text">{{ tipo || 'Ninguno' }}</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab 4: Impresión Global (muestra TODOS los componentes) -->
|
||
<div v-if="tabActiva === 'impresion-global'" class="tab-content cata-fade-in">
|
||
<h4 class="tab-section-title cata-text mb-4">
|
||
Visión Global Completa
|
||
</h4>
|
||
|
||
<!-- Sección: Organoléptica -->
|
||
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
||
<h5 class="global-section-title cata-text mb-4">Características Organolépticas</h5>
|
||
|
||
<!-- Selector de Familia de Fragancia/Aroma -->
|
||
<div class="form-section mb-4">
|
||
<CataSelectorFamilia
|
||
tipo="fragancia-aroma"
|
||
label="Familia de Fragancia y Aroma"
|
||
:model-value="muestra.fraganciaAromaNotas"
|
||
@update:model-value="actualizarFraganciaAroma"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Selector de Familia de Sabor -->
|
||
<div class="form-section">
|
||
<CataSelectorFamilia
|
||
tipo="sabor"
|
||
label="Familia de Sabor"
|
||
:model-value="muestra.saborNotas"
|
||
@update:model-value="actualizarSabor"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sección: Intensidades -->
|
||
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
||
<h5 class="global-section-title cata-text mb-4">Intensidades Descriptivas y Afectivas</h5>
|
||
|
||
<!-- Fragancia -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('fragancia') }">
|
||
<UIcon :name="getCategoryIcon('fragancia')" class="w-5 h-5" />
|
||
Fragancia
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('fragancia'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.fragancia.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('fragancia'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.fragancia.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.fragancia.descriptiva"
|
||
:color="getCategoryColor('fragancia')"
|
||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.fragancia.afectiva"
|
||
:color="getCategoryColor('fragancia')"
|
||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Aroma -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('aroma') }">
|
||
<UIcon :name="getCategoryIcon('aroma')" class="w-5 h-5" />
|
||
Aroma
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('aroma'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.aroma.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('aroma'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.aroma.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.aroma.descriptiva"
|
||
:color="getCategoryColor('aroma')"
|
||
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.aroma.afectiva"
|
||
:color="getCategoryColor('aroma')"
|
||
@update:model-value="(v) => actualizarIntensidad('aroma', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sabor -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('sabor') }">
|
||
<UIcon :name="getCategoryIcon('sabor')" class="w-5 h-5" />
|
||
Sabor
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sabor'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.sabor.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sabor'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.sabor.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.sabor.descriptiva"
|
||
:color="getCategoryColor('sabor')"
|
||
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.sabor.afectiva"
|
||
:color="getCategoryColor('sabor')"
|
||
@update:model-value="(v) => actualizarIntensidad('sabor', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sabor Residual -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('saborResidual') }">
|
||
<UIcon :name="getCategoryIcon('saborResidual')" class="w-5 h-5" />
|
||
Sabor Residual
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('saborResidual'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.saborResidual.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('saborResidual'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.saborResidual.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
||
:color="getCategoryColor('saborResidual')"
|
||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.saborResidual.afectiva"
|
||
:color="getCategoryColor('saborResidual')"
|
||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Acidez -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('acidez') }">
|
||
<UIcon :name="getCategoryIcon('acidez')" class="w-5 h-5" />
|
||
Acidez
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('acidez'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.acidez.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('acidez'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.acidez.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.acidez.descriptiva"
|
||
:color="getCategoryColor('acidez')"
|
||
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.acidez.afectiva"
|
||
:color="getCategoryColor('acidez')"
|
||
@update:model-value="(v) => actualizarIntensidad('acidez', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Dulzor -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('dulzor') }">
|
||
<UIcon :name="getCategoryIcon('dulzor')" class="w-5 h-5" />
|
||
Dulzor
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('dulzor'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.dulzor.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('dulzor'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.dulzor.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.dulzor.descriptiva"
|
||
:color="getCategoryColor('dulzor')"
|
||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.dulzor.afectiva"
|
||
:color="getCategoryColor('dulzor')"
|
||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sensación en Boca -->
|
||
<div class="form-section mb-4">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('sensacionBoca') }">
|
||
<UIcon :name="getCategoryIcon('sensacionBoca')" class="w-5 h-5" />
|
||
Sensación en la Boca
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sensacionBoca'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.sensacionBoca.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('sensacionBoca'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.sensacionBoca.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
||
:color="getCategoryColor('sensacionBoca')"
|
||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
||
:color="getCategoryColor('sensacionBoca')"
|
||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Impresión Global -->
|
||
<div class="form-section">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<h6 class="form-subsection-title cata-text flex items-center gap-2" :style="{ color: getCategoryColor('impresionGlobal') }">
|
||
<UIcon :name="getCategoryIcon('impresionGlobal')" class="w-5 h-5" />
|
||
Impresión Global
|
||
</h6>
|
||
<div class="flex gap-2">
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('impresionGlobal'), opacity: 0.4 }" class="text-xs">
|
||
📊 {{ muestra.intensidades.impresionGlobal.descriptiva ?? '-' }}
|
||
</UBadge>
|
||
<UBadge :style="{ backgroundColor: getCategoryColor('impresionGlobal'), opacity: 0.7 }" class="text-xs">
|
||
❤️ {{ muestra.intensidades.impresionGlobal.afectiva ?? '-' }}
|
||
</UBadge>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<CataSelectorIntensidad
|
||
tipo="descriptiva"
|
||
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
||
:color="getCategoryColor('impresionGlobal')"
|
||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
||
/>
|
||
<CataSelectorIntensidad
|
||
tipo="afectiva"
|
||
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
||
:color="getCategoryColor('impresionGlobal')"
|
||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'afectiva', v)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sección: Defectos -->
|
||
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
||
<h5 class="global-section-title cata-text mb-4">Defectos y Uniformidad</h5>
|
||
|
||
<!-- Tazas No Uniformes -->
|
||
<div class="form-section mb-4">
|
||
<CataSelectorTazas
|
||
tipo="uniformes"
|
||
label="Tazas NO Uniformes"
|
||
:model-value="muestra.tazasNoUniformes"
|
||
@update:model-value="actualizarTazasNoUniformes"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Tazas Defectuosas -->
|
||
<div class="form-section mb-4">
|
||
<CataSelectorTazas
|
||
tipo="defectuosas"
|
||
label="Tazas Defectuosas"
|
||
:model-value="muestra.tazasDefectuosas"
|
||
@update:model-value="actualizarTazasDefectuosas"
|
||
/>
|
||
</div>
|
||
|
||
<!-- Tipo de Defecto -->
|
||
<div v-if="muestra.tazasDefectuosas.length > 0" class="form-section">
|
||
<label class="block text-sm font-medium mb-2 cata-text">
|
||
Tipo de Defecto
|
||
</label>
|
||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
||
<button
|
||
v-for="tipo in tiposDefectos"
|
||
:key="tipo || 'ninguno'"
|
||
type="button"
|
||
:class="[
|
||
'cata-checkbox',
|
||
{ 'cata-checkbox-checked': muestra.defecto === tipo },
|
||
]"
|
||
@click="actualizarDefecto(tipo)"
|
||
>
|
||
<span class="cata-text">{{ tipo || 'Ninguno' }}</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sección: Detalles Adicionales -->
|
||
<div class="global-section mb-6 p-4 cata-outline-box rounded-lg">
|
||
<h5 class="global-section-title cata-text mb-4">Notas Adicionales</h5>
|
||
|
||
<!-- Otras Notas -->
|
||
<div class="form-section">
|
||
<label class="block text-sm font-medium mb-2 cata-text">
|
||
Otras Notas
|
||
</label>
|
||
<textarea
|
||
v-model="otrasNotasLocal"
|
||
class="cata-input w-full min-h-[100px] resize-y"
|
||
placeholder="Notas adicionales sobre el café, cuerpo, balance, etc..."
|
||
@blur="actualizarOtrasNotas"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Puntaje Final (solo lectura) -->
|
||
<div class="global-section p-4 cata-outline-box rounded-lg">
|
||
<div class="puntaje-final">
|
||
<div class="flex items-baseline justify-between">
|
||
<span class="text-sm cata-text opacity-75">Puntaje Final:</span>
|
||
<span class="text-3xl font-bold cata-text">{{ muestra.puntajeFinal }}</span>
|
||
</div>
|
||
<p class="text-xs cata-text opacity-60 mt-1">
|
||
Suma de valores afectivos
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { Muestra, NotaSeleccionada, TipoDefecto, SensacionBoca, GustoPredominante } from '~/types/catacion'
|
||
import type { TabCatacion, Subcategoria } from '~/composables/useCatacion'
|
||
import { SENSACIONES_BOCA, GUSTOS_PREDOMINANTES, TIPOS_DEFECTOS } from '~/types/catacion'
|
||
|
||
interface FormularioMuestraProps {
|
||
/** Muestra a editar */
|
||
muestra: Muestra
|
||
/** Tab activa */
|
||
tabActiva: TabCatacion
|
||
/** Subcategorías activas (filtros) */
|
||
subcategoriasActivas?: Subcategoria[]
|
||
}
|
||
|
||
const props = withDefaults(defineProps<FormularioMuestraProps>(), {
|
||
subcategoriasActivas: () => [],
|
||
})
|
||
|
||
const { actualizarIntensidad: actualizarIntensidadCatacion } = useCatacion()
|
||
const { getCategoryColor } = useCategoryColors()
|
||
|
||
// Función para obtener el icono de cada categoría
|
||
const getCategoryIcon = (category: string): string => {
|
||
const icons: Record<string, string> = {
|
||
fragancia: 'i-lucide-flower-2',
|
||
aroma: 'i-lucide-wind',
|
||
sabor: 'i-lucide-candy',
|
||
saborResidual: 'i-lucide-timer',
|
||
acidez: 'i-lucide-citrus',
|
||
dulzor: 'i-lucide-cookie',
|
||
sensacionBoca: 'i-lucide-droplets',
|
||
impresionGlobal: 'i-lucide-star',
|
||
}
|
||
return icons[category] || 'i-lucide-circle'
|
||
}
|
||
|
||
// Listas para los selectores
|
||
const sensacionesBoca = SENSACIONES_BOCA
|
||
const gustosPredominantes = GUSTOS_PREDOMINANTES
|
||
const tiposDefectos = TIPOS_DEFECTOS
|
||
|
||
// Helpers para filtrado por subcategorías
|
||
const deberMostrarSeccion = (subcategorias: Subcategoria[]): boolean => {
|
||
// Si no hay filtros activos, mostrar todo
|
||
if (!props.subcategoriasActivas || props.subcategoriasActivas.length === 0) return true
|
||
|
||
// Si hay filtros, verificar si alguno coincide
|
||
return subcategorias.some(sub => props.subcategoriasActivas?.includes(sub))
|
||
}
|
||
|
||
// Para Organoléptica
|
||
const mostrarFraganciaAroma = computed(() => deberMostrarSeccion(['fragancia-aroma']))
|
||
const mostrarSaborOrganoleptica = computed(() => deberMostrarSeccion(['sabor']))
|
||
const mostrarSensacionBocaOrganoleptica = computed(() => deberMostrarSeccion(['sensacion-boca']))
|
||
const mostrarGustosPredominantes = computed(() => deberMostrarSeccion(['gustos-predominantes']))
|
||
|
||
// Para Descriptiva/Afectiva
|
||
const mostrarFraganciaSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'fragancia']))
|
||
const mostrarAromaSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'aroma']))
|
||
const mostrarSaborSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'sabor']))
|
||
const mostrarSaborResidualSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'sabor-residual']))
|
||
const mostrarAcidezSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'acidez']))
|
||
const mostrarDulzorSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'dulzor']))
|
||
const mostrarSensacionBocaSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'sensacion-boca']))
|
||
const mostrarImpresionGlobalSlider = computed(() => deberMostrarSeccion(['descriptiva', 'afectiva', 'impresion-global']))
|
||
|
||
// Estado local para otras notas
|
||
const otrasNotasLocal = ref(props.muestra.otrasNotas)
|
||
|
||
// Actualizar intensidad
|
||
const actualizarIntensidad = async (
|
||
parametro: keyof Muestra['intensidades'],
|
||
tipo: 'descriptiva' | 'afectiva',
|
||
valor: number | null
|
||
) => {
|
||
await actualizarIntensidadCatacion(props.muestra.muestraId, parametro, tipo, valor)
|
||
}
|
||
|
||
// Actualizar fragancia/aroma
|
||
const { actualizarFraganciaAroma: actualizarFraganciaAromaCatacion } = useCatacion()
|
||
const actualizarFraganciaAroma = async (nota: NotaSeleccionada) => {
|
||
await actualizarFraganciaAromaCatacion(
|
||
props.muestra.muestraId,
|
||
nota.categorias,
|
||
nota.subcategorias,
|
||
nota.notaEspecifica
|
||
)
|
||
}
|
||
|
||
// Actualizar sabor
|
||
const { actualizarSabor: actualizarSaborCatacion } = useCatacion()
|
||
const actualizarSabor = async (nota: NotaSeleccionada) => {
|
||
await actualizarSaborCatacion(
|
||
props.muestra.muestraId,
|
||
nota.categorias,
|
||
nota.subcategorias,
|
||
nota.notaEspecifica
|
||
)
|
||
}
|
||
|
||
// Actualizar tazas
|
||
const { actualizarTazasNoUniformes: actualizarTazasNoUniformesCatacion, actualizarTazasDefectuosas: actualizarTazasDefectuosasCatacion } = useCatacion()
|
||
const actualizarTazasNoUniformes = async (tazas: number[]) => {
|
||
await actualizarTazasNoUniformesCatacion(props.muestra.muestraId, tazas)
|
||
}
|
||
|
||
const actualizarTazasDefectuosas = async (tazas: number[]) => {
|
||
await actualizarTazasDefectuosasCatacion(props.muestra.muestraId, tazas)
|
||
}
|
||
|
||
// Actualizar defecto
|
||
const { actualizarDefecto: actualizarDefectoCatacion } = useCatacion()
|
||
const actualizarDefecto = async (defecto: TipoDefecto) => {
|
||
await actualizarDefectoCatacion(props.muestra.muestraId, defecto)
|
||
}
|
||
|
||
// Seleccionar sensación en boca (selección única)
|
||
const { actualizarSensacionBoca } = useCatacion()
|
||
const seleccionarSensacionBoca = async (sensacion: SensacionBoca) => {
|
||
await actualizarSensacionBoca(props.muestra.muestraId, sensacion)
|
||
}
|
||
|
||
// Toggle gusto predominante
|
||
const { actualizarGustosPredominantes } = useCatacion()
|
||
const toggleGustoPredominante = async (gusto: GustoPredominante) => {
|
||
const gustos = [...props.muestra.gustosPredominantes]
|
||
const index = gustos.indexOf(gusto)
|
||
|
||
if (index > -1) {
|
||
gustos.splice(index, 1)
|
||
} else {
|
||
if (gustos.length >= 2) return // Máximo 2
|
||
gustos.push(gusto)
|
||
}
|
||
|
||
if (gustos.length === 0) return // Mínimo 1
|
||
|
||
await actualizarGustosPredominantes(props.muestra.muestraId, gustos)
|
||
}
|
||
|
||
// Actualizar otras notas
|
||
const { actualizarOtrasNotas: actualizarOtrasNotasCatacion } = useCatacion()
|
||
const actualizarOtrasNotas = async () => {
|
||
const notas = otrasNotasLocal.value.trim()
|
||
await actualizarOtrasNotasCatacion(props.muestra.muestraId, notas)
|
||
}
|
||
|
||
// Sincronizar otras notas cuando cambia la muestra
|
||
watch(() => props.muestra.otrasNotas, (newVal) => {
|
||
if (newVal !== otrasNotasLocal.value) {
|
||
otrasNotasLocal.value = newVal
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.formulario-muestra {
|
||
width: 100%;
|
||
}
|
||
|
||
.tab-section-title {
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
border-bottom: 1px solid;
|
||
padding-bottom: 0.5rem;
|
||
border-color: color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||
}
|
||
|
||
.global-section-title {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.form-section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.form-section-title {
|
||
font-size: 0.875rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
}
|
||
|
||
.form-subsection-title {
|
||
font-size: 0.8125rem;
|
||
font-weight: 700;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.puntaje-final {
|
||
text-align: center;
|
||
}
|
||
|
||
/* Grid de sensaciones y gustos - estilo compacto como subcategorías */
|
||
.sensaciones-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
.sensacion-item {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
padding: 0.375rem 0.5rem;
|
||
min-height: 32px;
|
||
}
|
||
|
||
.sensacion-item:focus {
|
||
outline: 2px solid transparent;
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.sensacion-item:focus-visible {
|
||
box-shadow: 0 0 0 2px var(--cata-primary);
|
||
}
|
||
|
||
.sensacion-text {
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
.gustos-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.375rem;
|
||
}
|
||
|
||
.gusto-item {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
padding: 0.375rem 0.5rem;
|
||
min-height: 32px;
|
||
}
|
||
|
||
.gusto-item:focus {
|
||
outline: 2px solid transparent;
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.gusto-item:focus-visible {
|
||
box-shadow: 0 0 0 2px var(--cata-primary);
|
||
}
|
||
|
||
.gusto-text {
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
/* Animaciones */
|
||
.sensacion-item.cata-checkbox-checked,
|
||
.gusto-item.cata-checkbox-checked {
|
||
transform: scale(1.02);
|
||
}
|
||
|
||
.sensacion-item:not(.disabled):hover,
|
||
.gusto-item:not(.disabled):hover {
|
||
transform: scale(1.02);
|
||
}
|
||
|
||
.sensacion-item:not(.disabled):active,
|
||
.gusto-item:not(.disabled):active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 640px) {
|
||
.sensacion-item {
|
||
min-height: 28px;
|
||
padding: 0.25rem 0.375rem;
|
||
}
|
||
|
||
.sensacion-text {
|
||
font-size: 0.6875rem;
|
||
}
|
||
|
||
.gusto-item {
|
||
min-height: 28px;
|
||
padding: 0.25rem 0.375rem;
|
||
}
|
||
|
||
.gusto-text {
|
||
font-size: 0.6875rem;
|
||
}
|
||
}
|
||
|
||
/* Touch-friendly */
|
||
@media (hover: none) and (pointer: coarse) {
|
||
.sensacion-item {
|
||
min-height: 36px;
|
||
}
|
||
|
||
.gusto-item {
|
||
min-height: 36px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.formulario-muestra {
|
||
padding: 0.75rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.tab-section-title {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.global-section-title {
|
||
font-size: 0.9rem;
|
||
}
|
||
}
|
||
</style>
|