Feat: Reemplazar sliders por selector de intensidad con iconos
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m6s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m6s
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
This commit is contained in:
@@ -90,13 +90,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.fragancia.descriptiva"
|
:model-value="muestra.intensidades.fragancia.descriptiva"
|
||||||
:color="getCategoryColor('fragancia')"
|
:color="getCategoryColor('fragancia')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.fragancia.afectiva"
|
:model-value="muestra.intensidades.fragancia.afectiva"
|
||||||
:color="getCategoryColor('fragancia')"
|
:color="getCategoryColor('fragancia')"
|
||||||
@@ -119,13 +119,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.aroma.descriptiva"
|
:model-value="muestra.intensidades.aroma.descriptiva"
|
||||||
:color="getCategoryColor('aroma')"
|
:color="getCategoryColor('aroma')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.aroma.afectiva"
|
:model-value="muestra.intensidades.aroma.afectiva"
|
||||||
:color="getCategoryColor('aroma')"
|
:color="getCategoryColor('aroma')"
|
||||||
@@ -148,13 +148,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.sabor.descriptiva"
|
:model-value="muestra.intensidades.sabor.descriptiva"
|
||||||
:color="getCategoryColor('sabor')"
|
:color="getCategoryColor('sabor')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.sabor.afectiva"
|
:model-value="muestra.intensidades.sabor.afectiva"
|
||||||
:color="getCategoryColor('sabor')"
|
:color="getCategoryColor('sabor')"
|
||||||
@@ -177,13 +177,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
||||||
:color="getCategoryColor('saborResidual')"
|
:color="getCategoryColor('saborResidual')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.saborResidual.afectiva"
|
:model-value="muestra.intensidades.saborResidual.afectiva"
|
||||||
:color="getCategoryColor('saborResidual')"
|
:color="getCategoryColor('saborResidual')"
|
||||||
@@ -206,13 +206,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.acidez.descriptiva"
|
:model-value="muestra.intensidades.acidez.descriptiva"
|
||||||
:color="getCategoryColor('acidez')"
|
:color="getCategoryColor('acidez')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.acidez.afectiva"
|
:model-value="muestra.intensidades.acidez.afectiva"
|
||||||
:color="getCategoryColor('acidez')"
|
:color="getCategoryColor('acidez')"
|
||||||
@@ -235,13 +235,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.dulzor.descriptiva"
|
:model-value="muestra.intensidades.dulzor.descriptiva"
|
||||||
:color="getCategoryColor('dulzor')"
|
:color="getCategoryColor('dulzor')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.dulzor.afectiva"
|
:model-value="muestra.intensidades.dulzor.afectiva"
|
||||||
:color="getCategoryColor('dulzor')"
|
:color="getCategoryColor('dulzor')"
|
||||||
@@ -264,13 +264,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
||||||
:color="getCategoryColor('sensacionBoca')"
|
:color="getCategoryColor('sensacionBoca')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
||||||
:color="getCategoryColor('sensacionBoca')"
|
:color="getCategoryColor('sensacionBoca')"
|
||||||
@@ -293,13 +293,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
||||||
:color="getCategoryColor('impresionGlobal')"
|
:color="getCategoryColor('impresionGlobal')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
||||||
:color="getCategoryColor('impresionGlobal')"
|
:color="getCategoryColor('impresionGlobal')"
|
||||||
@@ -406,13 +406,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.fragancia.descriptiva"
|
:model-value="muestra.intensidades.fragancia.descriptiva"
|
||||||
:color="getCategoryColor('fragancia')"
|
:color="getCategoryColor('fragancia')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('fragancia', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.fragancia.afectiva"
|
:model-value="muestra.intensidades.fragancia.afectiva"
|
||||||
:color="getCategoryColor('fragancia')"
|
:color="getCategoryColor('fragancia')"
|
||||||
@@ -435,13 +435,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.aroma.descriptiva"
|
:model-value="muestra.intensidades.aroma.descriptiva"
|
||||||
:color="getCategoryColor('aroma')"
|
:color="getCategoryColor('aroma')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('aroma', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.aroma.afectiva"
|
:model-value="muestra.intensidades.aroma.afectiva"
|
||||||
:color="getCategoryColor('aroma')"
|
:color="getCategoryColor('aroma')"
|
||||||
@@ -464,13 +464,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.sabor.descriptiva"
|
:model-value="muestra.intensidades.sabor.descriptiva"
|
||||||
:color="getCategoryColor('sabor')"
|
:color="getCategoryColor('sabor')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('sabor', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.sabor.afectiva"
|
:model-value="muestra.intensidades.sabor.afectiva"
|
||||||
:color="getCategoryColor('sabor')"
|
:color="getCategoryColor('sabor')"
|
||||||
@@ -493,13 +493,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
:model-value="muestra.intensidades.saborResidual.descriptiva"
|
||||||
:color="getCategoryColor('saborResidual')"
|
:color="getCategoryColor('saborResidual')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('saborResidual', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.saborResidual.afectiva"
|
:model-value="muestra.intensidades.saborResidual.afectiva"
|
||||||
:color="getCategoryColor('saborResidual')"
|
:color="getCategoryColor('saborResidual')"
|
||||||
@@ -522,13 +522,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.acidez.descriptiva"
|
:model-value="muestra.intensidades.acidez.descriptiva"
|
||||||
:color="getCategoryColor('acidez')"
|
:color="getCategoryColor('acidez')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('acidez', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.acidez.afectiva"
|
:model-value="muestra.intensidades.acidez.afectiva"
|
||||||
:color="getCategoryColor('acidez')"
|
:color="getCategoryColor('acidez')"
|
||||||
@@ -551,13 +551,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.dulzor.descriptiva"
|
:model-value="muestra.intensidades.dulzor.descriptiva"
|
||||||
:color="getCategoryColor('dulzor')"
|
:color="getCategoryColor('dulzor')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('dulzor', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.dulzor.afectiva"
|
:model-value="muestra.intensidades.dulzor.afectiva"
|
||||||
:color="getCategoryColor('dulzor')"
|
:color="getCategoryColor('dulzor')"
|
||||||
@@ -580,13 +580,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
:model-value="muestra.intensidades.sensacionBoca.descriptiva"
|
||||||
:color="getCategoryColor('sensacionBoca')"
|
:color="getCategoryColor('sensacionBoca')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('sensacionBoca', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
:model-value="muestra.intensidades.sensacionBoca.afectiva"
|
||||||
:color="getCategoryColor('sensacionBoca')"
|
:color="getCategoryColor('sensacionBoca')"
|
||||||
@@ -609,13 +609,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="descriptiva"
|
tipo="descriptiva"
|
||||||
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
:model-value="muestra.intensidades.impresionGlobal.descriptiva"
|
||||||
:color="getCategoryColor('impresionGlobal')"
|
:color="getCategoryColor('impresionGlobal')"
|
||||||
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
@update:model-value="(v) => actualizarIntensidad('impresionGlobal', 'descriptiva', v)"
|
||||||
/>
|
/>
|
||||||
<CataSliderIntensidad
|
<CataSelectorIntensidad
|
||||||
tipo="afectiva"
|
tipo="afectiva"
|
||||||
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
:model-value="muestra.intensidades.impresionGlobal.afectiva"
|
||||||
:color="getCategoryColor('impresionGlobal')"
|
:color="getCategoryColor('impresionGlobal')"
|
||||||
|
|||||||
267
nuxt4/app/components/cata/SelectorIntensidad.vue
Normal file
267
nuxt4/app/components/cata/SelectorIntensidad.vue
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
<template>
|
||||||
|
<div class="selector-intensidad cata-fade-in" :style="customColorStyle">
|
||||||
|
<!-- Contenedor de iconos -->
|
||||||
|
<div class="iconos-container">
|
||||||
|
<button
|
||||||
|
v-for="valor in iconos"
|
||||||
|
:key="valor"
|
||||||
|
type="button"
|
||||||
|
class="icono-item"
|
||||||
|
:class="{
|
||||||
|
'icono-activo': modelValue !== null && valor <= modelValue,
|
||||||
|
'icono-hover': valorHover !== null && valor <= valorHover,
|
||||||
|
'icono-descriptiva': tipo === 'descriptiva',
|
||||||
|
'icono-afectiva': tipo === 'afectiva',
|
||||||
|
}"
|
||||||
|
:disabled="disabled"
|
||||||
|
:title="`Valor: ${valor}`"
|
||||||
|
@click="handleClick(valor)"
|
||||||
|
@mouseenter="valorHover = valor"
|
||||||
|
@mouseleave="valorHover = null"
|
||||||
|
>
|
||||||
|
<!-- Icono para descriptiva: círculo -->
|
||||||
|
<UIcon
|
||||||
|
v-if="tipo === 'descriptiva'"
|
||||||
|
:name="(modelValue !== null && valor <= modelValue) || (valorHover !== null && valor <= valorHover)
|
||||||
|
? 'i-lucide-circle-dot'
|
||||||
|
: 'i-lucide-circle'"
|
||||||
|
class="icono"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Icono para afectiva: corazón -->
|
||||||
|
<UIcon
|
||||||
|
v-else
|
||||||
|
name="i-lucide-heart"
|
||||||
|
class="icono"
|
||||||
|
:class="{
|
||||||
|
'icono-filled': (modelValue !== null && valor <= modelValue) || (valorHover !== null && valor <= valorHover)
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Indicadores de valor -->
|
||||||
|
<div class="flex justify-between mt-2 text-xs cata-text opacity-60">
|
||||||
|
<span>{{ min }}</span>
|
||||||
|
<span v-if="modelValue !== null" class="font-semibold opacity-100">
|
||||||
|
{{ modelValue }}
|
||||||
|
</span>
|
||||||
|
<span>{{ max }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Descripción del tipo -->
|
||||||
|
<p v-if="showDescription" class="text-xs mt-1 cata-text opacity-75">
|
||||||
|
{{ tipoDescription }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface SelectorIntensidadProps {
|
||||||
|
/** Tipo de intensidad: descriptiva (1-10) o afectiva (1-15) */
|
||||||
|
tipo: 'descriptiva' | 'afectiva'
|
||||||
|
/** Valor actual del selector */
|
||||||
|
modelValue: number | null
|
||||||
|
/** Etiqueta del selector */
|
||||||
|
label?: string
|
||||||
|
/** ID para el input (auto-generado si no se provee) */
|
||||||
|
id?: string
|
||||||
|
/** Deshabilitar el selector */
|
||||||
|
disabled?: boolean
|
||||||
|
/** Marcar como requerido */
|
||||||
|
required?: boolean
|
||||||
|
/** Mostrar descripción del tipo */
|
||||||
|
showDescription?: boolean
|
||||||
|
/** Color personalizado para el selector */
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<SelectorIntensidadProps>(), {
|
||||||
|
disabled: false,
|
||||||
|
required: false,
|
||||||
|
showDescription: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:modelValue': [value: number | null]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Estado para el hover
|
||||||
|
const valorHover = ref<number | null>(null)
|
||||||
|
|
||||||
|
// Configuración según el tipo
|
||||||
|
const min = computed(() => 1)
|
||||||
|
const max = computed(() => props.tipo === 'descriptiva' ? 10 : 15)
|
||||||
|
|
||||||
|
// Array de valores para los iconos
|
||||||
|
const iconos = computed(() => {
|
||||||
|
return Array.from({ length: max.value }, (_, i) => i + 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Descripción del tipo de intensidad
|
||||||
|
const tipoDescription = computed(() => {
|
||||||
|
return props.tipo === 'descriptiva'
|
||||||
|
? 'Intensidad descriptiva: qué tan intensa es la característica (sin importar si es buena o mala)'
|
||||||
|
: 'Intensidad afectiva: qué tan buena o mala consideras esta característica'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Manejar click en un icono
|
||||||
|
const handleClick = (valor: number) => {
|
||||||
|
if (props.disabled) return
|
||||||
|
|
||||||
|
// Si clickean el mismo valor, lo deseleccionan (vuelve a null)
|
||||||
|
if (props.modelValue === valor) {
|
||||||
|
emit('update:modelValue', null)
|
||||||
|
} else {
|
||||||
|
emit('update:modelValue', valor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estilo dinámico para el color personalizado
|
||||||
|
const customColorStyle = computed(() => {
|
||||||
|
if (!props.color) return {}
|
||||||
|
return {
|
||||||
|
'--selector-custom-color': props.color,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.selector-intensidad {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconos-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-item {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0.25rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-item:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-item:not(:disabled):hover {
|
||||||
|
transform: scale(1.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-item:not(:disabled):active {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iconos */
|
||||||
|
.icono {
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iconos descriptiva (círculos) */
|
||||||
|
.icono-descriptiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--cata-primary) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-descriptiva.icono-activo .icono,
|
||||||
|
.icono-descriptiva.icono-hover .icono {
|
||||||
|
color: var(--cata-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iconos afectiva (corazones) */
|
||||||
|
.icono-afectiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--cata-primary) 40%, transparent);
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icono-afectiva.icono-activo .icono,
|
||||||
|
.icono-afectiva.icono-hover .icono {
|
||||||
|
color: var(--cata-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill para corazones activos */
|
||||||
|
.icono-filled {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color personalizado */
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-descriptiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--selector-custom-color) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-descriptiva.icono-activo .icono,
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-descriptiva.icono-hover .icono {
|
||||||
|
color: var(--selector-custom-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-afectiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--selector-custom-color) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-afectiva.icono-activo .icono,
|
||||||
|
.selector-intensidad[style*="--selector-custom-color"] .icono-afectiva.icono-hover .icono {
|
||||||
|
color: var(--selector-custom-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modo oscuro */
|
||||||
|
.dark .icono-descriptiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .icono-descriptiva.icono-activo .icono,
|
||||||
|
.dark .icono-descriptiva.icono-hover .icono {
|
||||||
|
color: var(--cata-primary);
|
||||||
|
filter: drop-shadow(0 0 4px var(--cata-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .icono-afectiva .icono {
|
||||||
|
color: color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .icono-afectiva.icono-activo .icono,
|
||||||
|
.dark .icono-afectiva.icono-hover .icono {
|
||||||
|
color: var(--cata-primary);
|
||||||
|
filter: drop-shadow(0 0 4px var(--cata-primary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color personalizado en modo oscuro */
|
||||||
|
.dark .selector-intensidad[style*="--selector-custom-color"] .icono-descriptiva.icono-activo .icono,
|
||||||
|
.dark .selector-intensidad[style*="--selector-custom-color"] .icono-descriptiva.icono-hover .icono {
|
||||||
|
filter: drop-shadow(0 0 4px var(--selector-custom-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .selector-intensidad[style*="--selector-custom-color"] .icono-afectiva.icono-activo .icono,
|
||||||
|
.dark .selector-intensidad[style*="--selector-custom-color"] .icono-afectiva.icono-hover .icono {
|
||||||
|
filter: drop-shadow(0 0 4px var(--selector-custom-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.icono {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconos-container {
|
||||||
|
gap: 0.15rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animación de fade in */
|
||||||
|
.selector-intensidad.cata-fade-in {
|
||||||
|
animation: cata-fade-in 0.3s ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user