2025-09-27 15:45:13 +00:00

152 lines
5.1 KiB
Vue

<script setup>
import GoogleIcon from '../Shared/GoogleIcon.vue';
import Loader from '../Shared/Loader.vue';
/** Eventos */
const emit = defineEmits([
'send-pagination'
]);
/** Propiedades */
const props = defineProps({
items: Object,
processing: Boolean
});
</script>
<template>
<div class="bg-white rounded-lg shadow-sm p-6 dark:bg-primary-d dark:border-primary/20 dark:text-primary-dt">
<!-- Tabla -->
<div class="overflow-x-auto">
<table v-if="!processing" class="w-full">
<thead>
<tr class="text-left text-sm text-gray-500 dark:text-primary-dt/70">
<slot name="head" />
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-primary/20 text-sm text-gray-700 dark:text-primary-dt">
<template v-if="items?.total > 0">
<slot
name="body"
:items="items?.data"
/>
</template>
<template v-else>
<tr>
<slot name="empty" />
</tr>
</template>
</tbody>
</table>
<!-- Estado de carga -->
<table v-else class="animate-pulse w-full">
<thead>
<tr>
<th colspan="100%" class="h-8 text-center">
<div class="flex items-center justify-center">
<Loader />
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="i in 3" :key="i">
<td colspan="100%" class="table-cell h-16 text-center">
<div class="w-full h-4 bg-secondary/50 rounded-md"></div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Paginación -->
<template v-if="items?.links && items.links.length > 3">
<div class="mt-6 flex w-full justify-end">
<div class="flex w-full justify-end flex-wrap space-x-1 -mb-1">
<template v-for="(link, k) in items.links" :key="k">
<!-- Botón anterior deshabilitado -->
<div v-if="link.url === null && k == 0"
class="px-3 py-2 text-sm leading-4 text-gray-400 border rounded-lg bg-gray-50 dark:bg-primary-d dark:border-primary/20"
>
<GoogleIcon name="arrow_back" class="w-4 h-4" />
</div>
<!-- Botón anterior activo -->
<button v-else-if="k === 0"
class="px-3 py-2 text-sm leading-4 border rounded-lg transition-colors duration-200 hover:bg-gray-50 dark:hover:bg-primary-d/50"
:class="{
'bg-primary text-white border-primary dark:bg-primary-dark dark:border-primary-dark': link.active,
'border-gray-300 dark:border-primary/20 text-gray-700 dark:text-primary-dt': !link.active
}"
@click="emit('send-pagination', link.url)"
>
<GoogleIcon name="arrow_back" class="w-4 h-4" />
</button>
<!-- Botón siguiente deshabilitado -->
<div v-else-if="link.url === null && k == (items.links.length - 1)"
class="px-3 py-2 text-sm leading-4 text-gray-400 border rounded-lg bg-gray-50 dark:bg-primary-d dark:border-primary/20"
>
<GoogleIcon name="arrow_forward" class="w-4 h-4" />
</div>
<!-- Botón siguiente activo -->
<button v-else-if="k === (items.links.length - 1)"
class="px-3 py-2 text-sm leading-4 border rounded-lg transition-colors duration-200 hover:bg-gray-50 dark:hover:bg-primary-d/50"
:class="{
'bg-primary text-white border-primary dark:bg-primary-dark dark:border-primary-dark': link.active,
'border-gray-300 dark:border-primary/20 text-gray-700 dark:text-primary-dt': !link.active
}"
@click="emit('send-pagination', link.url)"
>
<GoogleIcon name="arrow_forward" class="w-4 h-4" />
</button>
<!-- Números de página -->
<button v-else
class="px-3 py-2 text-sm leading-4 border rounded-lg transition-colors duration-200 hover:bg-gray-50 dark:hover:bg-primary-d/50"
:class="{
'bg-primary text-white border-primary dark:bg-primary-dark dark:border-primary-dark': link.active,
'border-gray-300 dark:border-primary/20 text-gray-700 dark:text-primary-dt': !link.active
}"
v-html="link.label"
@click="emit('send-pagination', link.url)"
></button>
</template>
</div>
</div>
</template>
</div>
</template>
<style scoped>
/* Estilos adicionales para mejorar la experiencia */
tbody tr {
transition: background-color 0.2s ease;
}
tbody tr:hover {
background-color: rgba(0, 0, 0, 0.02);
}
.dark tbody tr:hover {
background-color: rgba(255, 255, 255, 0.05);
}
/* Animación suave para los botones de paginación */
button {
transition: all 0.2s ease;
}
button:hover {
transform: translateY(-1px);
}
button:active {
transform: translateY(0);
}
</style>