From f151070db02b5107f3e81da6be7782156404e9f1 Mon Sep 17 00:00:00 2001 From: Edgar Mendez Mendoza Date: Thu, 6 Nov 2025 10:18:57 -0600 Subject: [PATCH] feat: enhance layout and sidebar with new menu items and animations --- components.d.ts | 2 + src/MainLayout.vue | 2 +- src/components/layout/Sidebar.vue | 240 ++++++++++++++++++++++++++---- src/components/layout/TopBar.vue | 147 ++++++++++++++++-- 4 files changed, 345 insertions(+), 46 deletions(-) diff --git a/components.d.ts b/components.d.ts index fe965d2..d1bfabc 100644 --- a/components.d.ts +++ b/components.d.ts @@ -13,11 +13,13 @@ declare module 'vue' { export interface GlobalComponents { AppConfig: typeof import('./src/components/layout/AppConfig.vue')['default'] AppTopbar: typeof import('./src/components/Holos/AppTopbar.vue')['default'] + Badge: typeof import('primevue/badge')['default'] Button: typeof import('primevue/button')['default'] Column: typeof import('primevue/column')['default'] DataTable: typeof import('primevue/datatable')['default'] HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] KpiCard: typeof import('./src/components/shared/KpiCard.vue')['default'] + Menu: typeof import('primevue/menu')['default'] Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] Tag: typeof import('primevue/tag')['default'] TopBar: typeof import('./src/components/layout/TopBar.vue')['default'] diff --git a/src/MainLayout.vue b/src/MainLayout.vue index c8a4212..1890a25 100644 --- a/src/MainLayout.vue +++ b/src/MainLayout.vue @@ -15,7 +15,7 @@ import WarehouseDashboard from './modules/warehouse/components/WarehouseDashboar -
+
diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index 6e2c16b..67c7713 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -11,30 +11,106 @@ interface MenuItem { const menuItems = ref([ { label: 'Dashboard', - icon: 'pi pi-home', + icon: 'pi pi-chart-line', to: '/' }, { - label: 'Almacén', - icon: 'pi pi-warehouse', + label: 'Ventas', + icon: 'pi pi-shopping-cart', items: [ - { label: 'Inventario', icon: 'pi pi-box', to: '/warehouse/inventory' }, - { label: 'Movimientos', icon: 'pi pi-arrow-right-arrow-left', to: '/warehouse/movements' } + { label: 'Nueva Venta', icon: 'pi pi-plus', to: '/ventas/nueva' }, + { label: 'Lista de Ventas', icon: 'pi pi-list', to: '/ventas/lista' }, + { label: 'Cotizaciones', icon: 'pi pi-file-edit', to: '/ventas/cotizaciones' } ] }, + { + label: 'Clientes', + icon: 'pi pi-users', + to: '/clientes' + }, + { + label: 'Inventario', + icon: 'pi pi-box', + to: '/inventario' + }, + { + label: 'Finanzas', + icon: 'pi pi-wallet', + items: [ + { label: 'Ingresos', icon: 'pi pi-arrow-up', to: '/finanzas/ingresos' }, + { label: 'Gastos', icon: 'pi pi-credit-card', to: '/finanzas/gastos' }, + { label: 'Cuentas por Cobrar', icon: 'pi pi-money-bill', to: '/finanzas/cobrar' } + ] + }, + { + label: 'Reportes', + icon: 'pi pi-chart-bar', + to: '/reportes' + }, + { + label: 'Documentos', + icon: 'pi pi-file', + to: '/documentos' + }, + { + label: 'Módulo Personalizado', + icon: 'pi pi-th-large', + to: '/modulo-personalizado' + }, { label: 'Configuración', icon: 'pi pi-cog', - to: '/settings' + to: '/configuracion' } ]); const sidebarVisible = ref(true); +const openItems = ref([]); +const currentRoute = ref(window.location.pathname); const toggleSidebar = () => { sidebarVisible.value = !sidebarVisible.value; }; +const toggleItem = (label: string) => { + const index = openItems.value.indexOf(label); + if (index > -1) { + openItems.value.splice(index, 1); + } else { + openItems.value.push(label); + } +}; + +const isItemOpen = (label: string) => { + return openItems.value.includes(label); +}; + +const isRouteActive = (to: string | undefined) => { + if (!to) return false; + return currentRoute.value === to; +}; + +// Simular cambio de ruta (en producción usarías Vue Router) +const navigateTo = (to: string) => { + currentRoute.value = to; + // window.history.pushState({}, '', to); +}; + +// Funciones de animación para los submenús +const onEnter = (el: Element) => { + const element = el as HTMLElement; + element.style.height = '0'; + element.offsetHeight; // Force reflow + element.style.height = element.scrollHeight + 'px'; +}; + +const onLeave = (el: Element) => { + const element = el as HTMLElement; + element.style.height = element.scrollHeight + 'px'; + element.offsetHeight; // Force reflow + element.style.height = '0'; +}; + defineExpose({ toggleSidebar }); @@ -47,15 +123,22 @@ defineExpose({ toggleSidebar }); >
-
+
- - - GOLS Control - + +
+
+

+ Golscontrols +

+

+ Sistema ERP +

+
@@ -67,29 +150,69 @@ defineExpose({ toggleSidebar }); - + {{ item.label }} - +
-
- - {{ item.label }} -
- + + + + + +
@@ -100,9 +223,10 @@ defineExpose({ toggleSidebar });
@@ -114,5 +238,57 @@ aside { height: 100vh; position: sticky; top: 0; + z-index: 40; +} + +/* Animación para submenús */ +.submenu-enter-active, +.submenu-leave-active { + transition: height 0.3s ease, opacity 0.3s ease; + overflow: hidden; +} + +.submenu-enter-from, +.submenu-leave-to { + height: 0; + opacity: 0; +} + +.submenu-enter-to, +.submenu-leave-from { + opacity: 1; +} + +/* Animación de rotación para el chevron */ +.rotate-180 { + transform: rotate(180deg); +} + +/* Efecto de sombra en item activo */ +.shadow-sm { + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +} + +/* Scroll suave */ +nav { + scrollbar-width: thin; + scrollbar-color: rgba(155, 155, 155, 0.5) transparent; +} + +nav::-webkit-scrollbar { + width: 6px; +} + +nav::-webkit-scrollbar-track { + background: transparent; +} + +nav::-webkit-scrollbar-thumb { + background-color: rgba(155, 155, 155, 0.5); + border-radius: 3px; +} + +nav::-webkit-scrollbar-thumb:hover { + background-color: rgba(155, 155, 155, 0.7); } diff --git a/src/components/layout/TopBar.vue b/src/components/layout/TopBar.vue index af6c9f6..5e2dc8a 100644 --- a/src/components/layout/TopBar.vue +++ b/src/components/layout/TopBar.vue @@ -1,32 +1,100 @@