Feat: Agregar vista expandida de ResumenMuestra
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m7s
Implementación completa de vista detallada para muestras: Componentes nuevos: - ResumenMuestraExpandido: Vista no compacta con valores claramente visibles - ModalResumenExpandido: Modal reutilizable para mostrar vista expandida Integraciones: - Calculadora SCAA: Usa vista expandida en paso 3 - Página de sesión: * Long press en móvil (500ms) en header del accordion * Botón expandir en desktop cerca del título * Vibración háptica en móvil al activar Características: - Grid responsivo de intensidades afectivas - Puntajes destacados (Σ y SCAA) con colores según valor - Visualización clara de penalizaciones - Diseño adaptativo móvil/desktop
This commit is contained in:
@@ -155,20 +155,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resumen de la muestra -->
|
||||
<div class="mt-6">
|
||||
<h4 class="text-sm font-semibold cata-text mb-2 opacity-75">
|
||||
Vista Previa
|
||||
</h4>
|
||||
<div class="cata-outline-box p-4 rounded-lg">
|
||||
<CataResumenMuestra :muestra="muestraGenerica" tab-activa="impresion-global" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Información adicional -->
|
||||
<div class="text-xs cata-text opacity-60 text-center">
|
||||
<p>Esta es una muestra de ejemplo para calcular el SCAA Score</p>
|
||||
<p>Los valores descriptivos y organolépticos están ocultos</p>
|
||||
<!-- Resumen de la muestra expandido -->
|
||||
<div class="mt-4">
|
||||
<CataResumenMuestraExpandido :muestra="muestraGenerica" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
72
nuxt4/app/components/cata/ModalResumenExpandido.vue
Normal file
72
nuxt4/app/components/cata/ModalResumenExpandido.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<UModal
|
||||
v-model:open="isOpen"
|
||||
:ui="{
|
||||
overlay: 'modal-overlay',
|
||||
content: 'cata-bg cata-outline-box max-w-3xl',
|
||||
header: 'cata-bg',
|
||||
body: 'cata-bg p-0',
|
||||
footer: 'cata-bg',
|
||||
title: 'cata-text'
|
||||
}"
|
||||
>
|
||||
<!-- Trigger (slot por defecto) -->
|
||||
<slot />
|
||||
|
||||
<!-- Título personalizado -->
|
||||
<template #title>
|
||||
<span class="cata-text">Resumen Detallado</span>
|
||||
</template>
|
||||
|
||||
<!-- Contenido del modal -->
|
||||
<template #body>
|
||||
<CataResumenMuestraExpandido :muestra="muestra" />
|
||||
</template>
|
||||
|
||||
<!-- Footer con botón -->
|
||||
<template #footer>
|
||||
<div class="flex justify-end w-full">
|
||||
<button
|
||||
class="cata-button px-4 py-2"
|
||||
@click="cerrar"
|
||||
>
|
||||
Cerrar
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Muestra } from '~/types/catacion'
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
muestra: Muestra
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: boolean]
|
||||
}>()
|
||||
|
||||
// Estado del modal
|
||||
const isOpen = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
})
|
||||
|
||||
const cerrar = () => {
|
||||
isOpen.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal-overlay {
|
||||
background-color: var(--cata-bg) !important;
|
||||
opacity: 0.95 !important;
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
}
|
||||
</style>
|
||||
437
nuxt4/app/components/cata/ResumenMuestraExpandido.vue
Normal file
437
nuxt4/app/components/cata/ResumenMuestraExpandido.vue
Normal file
@@ -0,0 +1,437 @@
|
||||
<template>
|
||||
<div class="resumen-expandido cata-text">
|
||||
<!-- Header con título y puntajes principales -->
|
||||
<div class="header-section">
|
||||
<div class="muestra-info">
|
||||
<div class="muestra-numero">#{{ muestra.muestraId }}</div>
|
||||
<h3 class="muestra-nombre">{{ muestra.nombre }}</h3>
|
||||
</div>
|
||||
|
||||
<!-- Puntajes destacados -->
|
||||
<div class="puntajes-principales">
|
||||
<div class="puntaje-grande puntaje-sumatoria">
|
||||
<div class="puntaje-label">Sumatoria Afectiva</div>
|
||||
<div class="puntaje-valor">{{ sumatoriaAfectiva }}</div>
|
||||
</div>
|
||||
|
||||
<div class="puntaje-grande puntaje-scaa" :class="scaaClass">
|
||||
<div class="puntaje-label">SCAA Score</div>
|
||||
<div class="puntaje-valor">{{ scaaScore.toFixed(2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Intensidades Afectivas -->
|
||||
<div class="seccion">
|
||||
<h4 class="seccion-titulo">Valores Afectivos</h4>
|
||||
<div class="intensidades-grid">
|
||||
<div v-if="muestra.intensidades.fragancia.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('fragancia')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Fragancia</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.fragancia.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.aroma.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('aroma')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Aroma</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.aroma.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.sabor.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('sabor')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Sabor</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.sabor.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.saborResidual.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('saborResidual')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Sabor Residual</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.saborResidual.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.acidez.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('acidez')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Acidez</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.acidez.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.dulzor.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('dulzor')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Dulzor</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.dulzor.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.sensacionBoca.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('sensacionBoca')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Sensación en Boca</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.sensacionBoca.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.intensidades.impresionGlobal.afectiva !== null" class="intensidad-item">
|
||||
<UIcon :name="getCategoryIcon('impresionGlobal')" class="intensidad-icon" />
|
||||
<div class="intensidad-info">
|
||||
<div class="intensidad-nombre">Impresión Global</div>
|
||||
<div class="intensidad-valor">{{ muestra.intensidades.impresionGlobal.afectiva }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Defectos (si existen) -->
|
||||
<div v-if="muestra.tazasNoUniformes.length > 0 || muestra.tazasDefectuosas.length > 0" class="seccion">
|
||||
<h4 class="seccion-titulo">Penalizaciones</h4>
|
||||
<div class="defectos-info">
|
||||
<div v-if="muestra.tazasNoUniformes.length > 0" class="defecto-item defecto-warning">
|
||||
<UIcon name="i-lucide-alert-circle" class="defecto-icon" />
|
||||
<div>
|
||||
<div class="defecto-label">Tazas No Uniformes</div>
|
||||
<div class="defecto-detalle">{{ muestra.tazasNoUniformes.length }} taza(s) - {{ muestra.tazasNoUniformes.join(', ') }}</div>
|
||||
<div class="defecto-penalizacion">-{{ muestra.tazasNoUniformes.length * 2 }} puntos</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muestra.tazasDefectuosas.length > 0" class="defecto-item defecto-error">
|
||||
<UIcon name="i-lucide-x-circle" class="defecto-icon" />
|
||||
<div>
|
||||
<div class="defecto-label">Tazas Defectuosas</div>
|
||||
<div class="defecto-detalle">{{ muestra.tazasDefectuosas.length }} taza(s) - {{ muestra.tazasDefectuosas.join(', ') }}</div>
|
||||
<div v-if="muestra.defecto" class="defecto-tipo">Tipo: {{ muestra.defecto }}</div>
|
||||
<div class="defecto-penalizacion">-{{ muestra.tazasDefectuosas.length * 4 }} puntos</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Muestra } from '~/types/catacion'
|
||||
import { calcularSumatoriaAfectiva, calcularSCAA } from '~/types/catacion'
|
||||
|
||||
interface Props {
|
||||
muestra: Muestra
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// Cálculos de puntajes
|
||||
const sumatoriaAfectiva = computed(() => calcularSumatoriaAfectiva(props.muestra))
|
||||
const scaaScore = computed(() => calcularSCAA(props.muestra))
|
||||
|
||||
// Clase CSS para el SCAA Score basado en el valor
|
||||
const scaaClass = computed(() => {
|
||||
const scaa = scaaScore.value
|
||||
if (scaa >= 90) return 'scaa-excelente'
|
||||
if (scaa >= 85) return 'scaa-muy-bueno'
|
||||
if (scaa >= 80) return 'scaa-bueno'
|
||||
if (scaa >= 70) return 'scaa-regular'
|
||||
return 'scaa-bajo'
|
||||
})
|
||||
|
||||
// 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'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resumen-expandido {
|
||||
padding: 1.5rem;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Header Section */
|
||||
.header-section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.muestra-info {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.muestra-numero {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
opacity: 0.6;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.muestra-nombre {
|
||||
font-size: 1.75rem;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Puntajes Principales */
|
||||
.puntajes-principales {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.puntaje-grande {
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.75rem;
|
||||
border: 2px solid;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.puntaje-label {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.75;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.puntaje-valor {
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.puntaje-sumatoria {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 15%, transparent);
|
||||
border-color: color-mix(in srgb, var(--cata-primary) 40%, transparent);
|
||||
color: var(--cata-text);
|
||||
}
|
||||
|
||||
/* SCAA Score Colors */
|
||||
.scaa-excelente {
|
||||
background-color: color-mix(in srgb, #10b981 20%, transparent);
|
||||
border-color: #10b981;
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.scaa-muy-bueno {
|
||||
background-color: color-mix(in srgb, #3b82f6 20%, transparent);
|
||||
border-color: #3b82f6;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.scaa-bueno {
|
||||
background-color: color-mix(in srgb, #f59e0b 20%, transparent);
|
||||
border-color: #f59e0b;
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.scaa-regular {
|
||||
background-color: color-mix(in srgb, #ef4444 20%, transparent);
|
||||
border-color: #ef4444;
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.scaa-bajo {
|
||||
background-color: color-mix(in srgb, #6b7280 20%, transparent);
|
||||
border-color: #6b7280;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* Secciones */
|
||||
.seccion {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.seccion-titulo {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Intensidades Grid */
|
||||
.intensidades-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.intensidad-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 10%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||||
}
|
||||
|
||||
.intensidad-icon {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
color: var(--cata-primary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.intensidad-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.intensidad-nombre {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.75;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.intensidad-valor {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Defectos */
|
||||
.defectos-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.defecto-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.defecto-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
margin-top: 0.125rem;
|
||||
}
|
||||
|
||||
.defecto-label {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.defecto-detalle {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.defecto-tipo {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.defecto-penalizacion {
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.defecto-warning {
|
||||
background-color: color-mix(in srgb, #f59e0b 15%, transparent);
|
||||
border-color: #f59e0b;
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.defecto-error {
|
||||
background-color: color-mix(in srgb, #ef4444 15%, transparent);
|
||||
border-color: #ef4444;
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
/* Modo oscuro */
|
||||
.dark .puntaje-sumatoria {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 20%, transparent);
|
||||
}
|
||||
|
||||
.dark .scaa-excelente {
|
||||
background-color: color-mix(in srgb, #10b981 30%, transparent);
|
||||
}
|
||||
|
||||
.dark .scaa-muy-bueno {
|
||||
background-color: color-mix(in srgb, #3b82f6 30%, transparent);
|
||||
}
|
||||
|
||||
.dark .scaa-bueno {
|
||||
background-color: color-mix(in srgb, #f59e0b 30%, transparent);
|
||||
}
|
||||
|
||||
.dark .scaa-regular {
|
||||
background-color: color-mix(in srgb, #ef4444 30%, transparent);
|
||||
}
|
||||
|
||||
.dark .scaa-bajo {
|
||||
background-color: color-mix(in srgb, #6b7280 30%, transparent);
|
||||
}
|
||||
|
||||
.dark .intensidad-item {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 15%, transparent);
|
||||
}
|
||||
|
||||
.dark .defecto-warning {
|
||||
background-color: color-mix(in srgb, #f59e0b 20%, transparent);
|
||||
}
|
||||
|
||||
.dark .defecto-error {
|
||||
background-color: color-mix(in srgb, #ef4444 20%, transparent);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 640px) {
|
||||
.resumen-expandido {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.muestra-nombre {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.puntajes-principales {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.puntaje-valor {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.intensidades-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.intensidad-item {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.intensidad-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.intensidad-valor {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -167,10 +167,25 @@
|
||||
>
|
||||
<!-- Header personalizado con ResumenMuestra -->
|
||||
<template #default="{ item }">
|
||||
<div
|
||||
class="resumen-wrapper"
|
||||
@touchstart="(e) => onTouchStart(e, item.muestra)"
|
||||
@touchend="onTouchEnd"
|
||||
@touchcancel="onTouchEnd"
|
||||
>
|
||||
<CataResumenMuestra
|
||||
:muestra="item.muestra"
|
||||
:tab-activa="tabActiva"
|
||||
/>
|
||||
<!-- Botón para vista expandida (solo desktop) -->
|
||||
<button
|
||||
class="boton-expandir hidden sm:flex"
|
||||
@click.stop="abrirVistaExpandida(item.muestra)"
|
||||
title="Ver resumen detallado"
|
||||
>
|
||||
<UIcon name="i-lucide-expand" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Content con FormularioMuestra -->
|
||||
@@ -203,6 +218,13 @@
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal de vista expandida -->
|
||||
<CataModalResumenExpandido
|
||||
v-if="muestraExpandida"
|
||||
v-model="mostrarModalExpandido"
|
||||
:muestra="muestraExpandida"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -383,6 +405,37 @@ const toggleSubcategoria = (subcategoria: Subcategoria) => {
|
||||
actualizarSubcategorias(actuales)
|
||||
}
|
||||
|
||||
// Modal de vista expandida
|
||||
const mostrarModalExpandido = ref(false)
|
||||
const muestraExpandida = ref<Muestra | null>(null)
|
||||
|
||||
// Abrir vista expandida
|
||||
const abrirVistaExpandida = (muestra: Muestra) => {
|
||||
muestraExpandida.value = muestra
|
||||
mostrarModalExpandido.value = true
|
||||
}
|
||||
|
||||
// Long press en móvil
|
||||
let longPressTimer: NodeJS.Timeout | null = null
|
||||
const LONG_PRESS_DURATION = 500 // ms
|
||||
|
||||
const onTouchStart = (event: TouchEvent, muestra: Muestra) => {
|
||||
longPressTimer = setTimeout(() => {
|
||||
// Vibrar si está disponible
|
||||
if (navigator.vibrate) {
|
||||
navigator.vibrate(50)
|
||||
}
|
||||
abrirVistaExpandida(muestra)
|
||||
}, LONG_PRESS_DURATION)
|
||||
}
|
||||
|
||||
const onTouchEnd = () => {
|
||||
if (longPressTimer) {
|
||||
clearTimeout(longPressTimer)
|
||||
longPressTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
// Formatear fecha
|
||||
const formatearFecha = (fecha: string): string => {
|
||||
const date = new Date(fecha)
|
||||
@@ -535,6 +588,45 @@ onMounted(() => {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 10%, transparent);
|
||||
}
|
||||
|
||||
/* Wrapper de resumen con botón expandir */
|
||||
.resumen-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.boton-expandir {
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 10%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--cata-primary) 30%, transparent);
|
||||
color: var(--cata-primary);
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.boton-expandir:hover {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 20%, transparent);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.boton-expandir:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.dark .boton-expandir {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 15%, transparent);
|
||||
}
|
||||
|
||||
.dark .boton-expandir:hover {
|
||||
background-color: color-mix(in srgb, var(--cata-primary) 25%, transparent);
|
||||
}
|
||||
|
||||
/* Floating action button */
|
||||
.floating-action {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user