2025-09-23 13:50:25 -06:00

141 lines
5.0 KiB
Vue

<script setup>
import { ref, computed } from 'vue';
import GoogleIcon from '@Shared/GoogleIcon.vue';
/** Propiedades */
const props = defineProps({
modelValue: {
type: String,
default: 'A4'
}
});
/** Eventos */
const emit = defineEmits(['update:modelValue']);
/** Referencias */
const isOpen = ref(false);
/** Tamaños de página disponibles */
const pageSizes = [
{
name: 'A4',
label: 'A4 (210 x 297 mm)',
width: 794,
height: 1123,
description: 'Estándar internacional'
},
{
name: 'A3',
label: 'A3 (297 x 420 mm)',
width: 1123,
height: 1587,
description: 'Doble de A4'
},
{
name: 'Letter',
label: 'Carta (216 x 279 mm)',
width: 816,
height: 1056,
description: 'Estándar US'
},
{
name: 'Legal',
label: 'Oficio (216 x 356 mm)',
width: 816,
height: 1344,
description: 'Legal US'
},
{
name: 'Tabloid',
label: 'Tabloide (279 x 432 mm)',
width: 1056,
height: 1632,
description: 'Doble carta'
}
];
/** Propiedades computadas */
const selectedSize = computed(() => {
return pageSizes.find(size => size.name === props.modelValue) || pageSizes[0];
});
/** Métodos */
const selectSize = (size) => {
emit('update:modelValue', size.name);
isOpen.value = false;
};
</script>
<template>
<div class="relative">
<!-- Selector principal -->
<button
@click="isOpen = !isOpen"
class="flex items-center gap-2 px-3 py-2 text-sm bg-white dark:bg-primary-d border border-gray-200 dark:border-primary/20 rounded-md hover:bg-gray-50 dark:hover:bg-primary/10 transition-colors"
>
<GoogleIcon name="aspect_ratio" class="text-gray-500 dark:text-primary-dt/70" />
<span class="text-gray-700 dark:text-primary-dt">{{ selectedSize.name }}</span>
<GoogleIcon
name="expand_more"
class="text-gray-400 dark:text-primary-dt/50 transition-transform"
:class="{ 'rotate-180': isOpen }"
/>
</button>
<!-- Dropdown -->
<div
v-if="isOpen"
@click.away="isOpen = false"
class="absolute top-full left-0 mt-1 w-72 bg-white dark:bg-primary-d border border-gray-200 dark:border-primary/20 rounded-lg shadow-lg z-50 py-2"
>
<div class="px-3 py-2 text-xs font-semibold text-gray-500 dark:text-primary-dt/70 uppercase tracking-wider border-b border-gray-100 dark:border-primary/20">
Tamaños de página
</div>
<div class="max-h-64 overflow-y-auto">
<button
v-for="size in pageSizes"
:key="size.name"
@click="selectSize(size)"
class="w-full flex items-center gap-3 px-3 py-3 hover:bg-gray-50 dark:hover:bg-primary/10 transition-colors text-left"
:class="{
'bg-blue-50 dark:bg-blue-900/20': selectedSize.name === size.name
}"
>
<div class="flex-shrink-0">
<div
class="w-8 h-10 border border-gray-300 dark:border-primary/30 rounded-sm bg-white dark:bg-primary-d flex items-center justify-center"
:class="{
'border-blue-500 dark:border-blue-400': selectedSize.name === size.name
}"
>
<div
class="bg-gray-200 dark:bg-primary/20 rounded-sm"
:style="{
width: `${Math.min(20, (size.width / size.height) * 32)}px`,
height: `${Math.min(32, (size.height / size.width) * 20)}px`
}"
:class="{
'bg-blue-200 dark:bg-blue-800': selectedSize.name === size.name
}"
></div>
</div>
</div>
<div class="flex-1 min-w-0">
<div class="font-medium text-gray-900 dark:text-primary-dt">{{ size.label }}</div>
<div class="text-xs text-gray-500 dark:text-primary-dt/70">{{ size.description }}</div>
<div class="text-xs text-gray-400 dark:text-primary-dt/50 mt-1">
{{ size.width }} x {{ size.height }} px
</div>
</div>
<div v-if="selectedSize.name === size.name" class="flex-shrink-0">
<GoogleIcon name="check" class="text-blue-500 dark:text-blue-400" />
</div>
</button>
</div>
</div>
</div>
</template>