feat: show past bus in ETACard and move disclaimer to tooltip
This commit is contained in:
@ -27,6 +27,37 @@
|
||||
Desliza hacia abajo para minimizar
|
||||
</p>
|
||||
|
||||
<!-- Tooltip informativo en la esquina superior derecha -->
|
||||
<div class="absolute top-4 right-5 z-20">
|
||||
<button
|
||||
@click="showTooltip = !showTooltip"
|
||||
class="flex items-center justify-center w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-800 text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
<span class="material-icons text-xl">info</span>
|
||||
</button>
|
||||
|
||||
<!-- Contenido del Tooltip -->
|
||||
<Transition name="fade">
|
||||
<div
|
||||
v-if="showTooltip"
|
||||
class="absolute top-10 right-0 w-64 p-4 bg-gray-900/95 dark:bg-white/95 text-white dark:text-gray-900 rounded-2xl shadow-2xl backdrop-blur-sm text-[11px] leading-relaxed border border-white/20 dark:border-gray-200 pointer-events-auto"
|
||||
>
|
||||
<div class="flex items-start gap-2 mb-2">
|
||||
<span class="material-icons text-yellow-400 text-sm">warning</span>
|
||||
<span class="font-bold uppercase tracking-wider text-[10px]">Información de horarios</span>
|
||||
</div>
|
||||
<p class="opacity-90">
|
||||
Este es un tiempo estimado basado en la velocidad promedio. <strong>No existe rastreo GPS en tiempo real.</strong>
|
||||
</p>
|
||||
<p class="mt-2 opacity-90">
|
||||
El tráfico y paradas intermedias pueden alterar el tiempo de llegada dramáticamente.
|
||||
</p>
|
||||
<!-- Flecha del tooltip -->
|
||||
<div class="absolute -top-1.5 right-3.5 w-3 h-3 bg-gray-900/95 dark:bg-white/95 rotate-45 border-l border-t border-white/20 dark:border-gray-200"></div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<!-- Cabecera de la parada -->
|
||||
<div v-if="stopName && !isLoading" class="mt-4 flex items-start gap-4 pb-4 border-b border-gray-100 dark:border-gray-800">
|
||||
<div class="bg-blue-100 dark:bg-blue-900/40 p-3 rounded-2xl flex-shrink-0">
|
||||
@ -64,13 +95,16 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Lista de llegadas (Max 2) -->
|
||||
<!-- Lista de llegadas (Próximos + Pasado) -->
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="(bus, index) in buses.slice(0, 2)"
|
||||
v-for="bus in displayBuses"
|
||||
:key="bus.horario_id"
|
||||
class="group bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl p-4 flex items-center justify-between"
|
||||
:class="{ 'ring-2 ring-green-500/50 dark:ring-green-400/50 bg-green-50/30 dark:bg-green-900/10': bus.estado === 'en_camino' }"
|
||||
class="group bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl p-4 flex items-center justify-between transition-all"
|
||||
:class="{
|
||||
'ring-2 ring-green-500/50 dark:ring-green-400/50 bg-green-50/30 dark:bg-green-900/10': bus.estado === 'en_camino',
|
||||
'opacity-60 grayscale-[0.5]': bus.estado === 'pasó'
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<!-- Icono dinámico según estado -->
|
||||
@ -87,7 +121,7 @@
|
||||
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold text-gray-900 dark:text-white line-clamp-1">
|
||||
{{ index === 0 ? 'Bus más cercano' : 'Siguiente bus' }}
|
||||
{{ bus.label }}
|
||||
</span>
|
||||
<div class="flex flex-col mt-0.5 gap-0.5">
|
||||
<span class="text-xs font-semibold text-gray-500 dark:text-gray-400 flex items-center gap-1">
|
||||
@ -119,7 +153,7 @@
|
||||
<span v-else-if="bus.estado === 'próximo'" class="inline-flex px-2.5 py-1 rounded-lg bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-400 text-[10px] font-black uppercase tracking-wider">
|
||||
Programado
|
||||
</span>
|
||||
<span v-else class="inline-flex px-2.5 py-1 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400 text-[10px] font-black uppercase tracking-wider line-through">
|
||||
<span v-else class="inline-flex px-2.5 py-1 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400 text-[10px] font-black uppercase tracking-wider">
|
||||
Ya pasó
|
||||
</span>
|
||||
</div>
|
||||
@ -128,28 +162,21 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Legal Disclaimer Intocable -->
|
||||
<div v-if="stopName" class="mt-2 p-3 bg-yellow-50 dark:bg-yellow-900/20 rounded-xl flex items-start gap-3 border border-yellow-100 dark:border-yellow-900/50">
|
||||
<span class="material-icons text-yellow-600 dark:text-yellow-500 text-lg mt-0.5 shrink-0">info</span>
|
||||
<p class="text-[11px] leading-snug text-yellow-800 dark:text-yellow-600/90 font-medium">
|
||||
<strong>Aviso:</strong> Este es un tiempo estimado basado en la velocidad promedio de las unidades en la ciudad. No existe rastreo GPS en tiempo real.
|
||||
El tráfico y paradas intermedias pueden alterar el tiempo de llegada dramáticamente.
|
||||
</p>
|
||||
</div>
|
||||
<!-- Disclaimer removed from bottom and moved to tooltip bubble -->
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import type { BusETA } from '@/composables/useETA';
|
||||
import { formatDurationMinutes } from '@/utils/durationFormatter';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
isOpen: boolean;
|
||||
stopName: string;
|
||||
walkDistance: number;
|
||||
@ -163,6 +190,27 @@ const emit = defineEmits<{
|
||||
(e: 'refresh'): void;
|
||||
}>();
|
||||
|
||||
// Tooltip state
|
||||
const showTooltip = ref(false);
|
||||
|
||||
// Categorización de buses
|
||||
const upcomingBuses = computed(() => props.buses.filter(b => b.estado !== 'pasó'));
|
||||
const lastPastBus = computed(() => {
|
||||
const pastBuses = props.buses.filter(b => b.estado === 'pasó');
|
||||
// useETA ordena por etaMinutos asc, así que en negativos (-20, -10, -5) el último es el más reciente
|
||||
return pastBuses.length > 0 ? pastBuses[pastBuses.length - 1] : null;
|
||||
});
|
||||
|
||||
const displayBuses = computed(() => {
|
||||
const result = [];
|
||||
// Agregamos los dos próximos
|
||||
if (upcomingBuses.value[0]) result.push({ ...upcomingBuses.value[0], label: 'Bus más cercano' });
|
||||
if (upcomingBuses.value[1]) result.push({ ...upcomingBuses.value[1], label: 'Siguiente bus' });
|
||||
// Agregamos el que ya pasó
|
||||
if (lastPastBus.value) result.push({ ...lastPastBus.value, label: 'Bus anterior' });
|
||||
return result;
|
||||
});
|
||||
|
||||
// ── DRAG TO DISMISS ──────────────────────────────────
|
||||
const sheetRef = ref<HTMLElement | null>(null);
|
||||
const dragY = ref(0); // desplazamiento actual del drag
|
||||
@ -244,4 +292,16 @@ onUnmounted(() => {
|
||||
.fixed.inset-0 {
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
/* Transición para el Tooltip */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.2s ease-out;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(10px) scale(0.95);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user