feat: agregar menú dropdown de configuración compacto
- Crear componente SettingsMenu.client.vue con tres puntos verticales - Agrupar AuthIndicator y ThemeToggle en dropdown menu - Reducir espacio en barra principal para diseño más compacto - Agregar animaciones y transiciones suaves al dropdown - Cerrar menú automáticamente al hacer clic fuera o presionar Escape
This commit is contained in:
197
components/SettingsMenu.client.vue
Normal file
197
components/SettingsMenu.client.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="settings-menu" ref="menuContainer">
|
||||
<IconButton
|
||||
:icon="MoreVertical"
|
||||
title="Configuración"
|
||||
size="small"
|
||||
@click="toggleMenu"
|
||||
class="menu-trigger"
|
||||
:active="isOpen"
|
||||
/>
|
||||
|
||||
<transition name="dropdown">
|
||||
<div v-if="isOpen" class="dropdown-menu glass">
|
||||
<div class="menu-section">
|
||||
<div class="menu-label">Autenticación</div>
|
||||
<AuthIndicator class="menu-item-auth" />
|
||||
</div>
|
||||
|
||||
<div class="menu-divider"></div>
|
||||
|
||||
<div class="menu-section">
|
||||
<div class="menu-label">Tema</div>
|
||||
<div class="menu-item">
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { MoreVertical } from 'lucide-vue-next'
|
||||
import IconButton from './IconButton.client.vue'
|
||||
import AuthIndicator from './AuthIndicator.client.vue'
|
||||
import ThemeToggle from './ThemeToggle.client.vue'
|
||||
|
||||
const isOpen = ref(false)
|
||||
const menuContainer = ref(null)
|
||||
|
||||
const toggleMenu = () => {
|
||||
isOpen.value = !isOpen.value
|
||||
}
|
||||
|
||||
const closeMenu = () => {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
// Cerrar el menú al hacer clic fuera
|
||||
const handleClickOutside = (event) => {
|
||||
if (menuContainer.value && !menuContainer.value.contains(event.target)) {
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
||||
// Cerrar el menú al presionar Escape
|
||||
const handleEscape = (event) => {
|
||||
if (event.key === 'Escape' && isOpen.value) {
|
||||
closeMenu()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
document.addEventListener('keydown', handleEscape)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
document.removeEventListener('keydown', handleEscape)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.settings-menu {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.menu-trigger:hover {
|
||||
animation: pulse-menu 0.6s ease-in-out;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
min-width: 220px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-radius: 16px;
|
||||
padding: 12px;
|
||||
box-shadow: var(--shadow-glass), 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.menu-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 0 8px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.menu-item-auth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Ajustar el AuthIndicator para que se vea bien en el menú */
|
||||
.menu-item-auth :deep(.auth-indicator) {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.menu-divider {
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.2),
|
||||
transparent
|
||||
);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
.dropdown-enter-active,
|
||||
.dropdown-leave-active {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform-origin: top right;
|
||||
}
|
||||
|
||||
.dropdown-enter-from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
|
||||
.dropdown-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-10px);
|
||||
}
|
||||
|
||||
@keyframes pulse-menu {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.1); }
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.dropdown-menu {
|
||||
min-width: 200px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.dropdown-menu {
|
||||
/* En móvil, centrar mejor el menú */
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user