ADD: Crear componente Dropdown para el sidebar

This commit is contained in:
Juan Felipe Zapata Moreno 2025-09-23 11:34:48 -06:00
parent c6aa67a7f8
commit 38f46cef84
10 changed files with 206 additions and 163 deletions

View File

@ -0,0 +1,27 @@
<script setup>
import GoogleIcon from "@Shared/GoogleIcon.vue";
defineProps({
type: {
default: "button",
type: String,
},
icon: {
default: "add",
type: String,
},
text: {
default: "",
type: String,
}
});
</script>
<template>
<button
:type="type"
class="inline-flex items-center gap-3 bg-[#2563eb] hover:bg-[#1e40af] text-white px-4 py-2 rounded-full shadow-md"
>
<GoogleIcon :name="icon" />
<span>{{ text }}</span>
</button>
</template>

View File

@ -0,0 +1,78 @@
<script setup>
import { ref, computed } from "vue";
import { RouterLink, useRoute } from "vue-router";
import useLeftSidebar from "@Stores/LeftSidebar";
import GoogleIcon from "@Shared/GoogleIcon.vue";
/** Definidores */
const leftSidebar = useLeftSidebar();
const vroute = useRoute();
/** Propiedades */
const props = defineProps({
name: String,
icon: String,
to: String,
active: {
type: Boolean,
default: false,
},
collapsed: {
type: Boolean,
default: false,
},
});
const isCollapsed = ref(props.collapsed);
const closeSidebar = () => {
if (TwScreen.isDevice("phone") || TwScreen.isDevice("tablet")) {
leftSidebar.close();
}
};
const isActive = computed(() => props.active || props.to === vroute.name);
const classes = computed(() => {
return isActive.value
? "flex items-center px-4 py-2 mx-2 my-1 text-white !bg-blue-600 rounded-lg transition-all duration-200 !border-transparent"
: "flex items-center px-4 py-2 mx-2 my-1 text-gray-600 hover:bg-gray-100 rounded-lg transition-all duration-200";
});
</script>
<template>
<ul>
<li class="hidden md:block">
<div class="flex items-center px-2 py-2 rounded">
<button
class="dropdown-toggle w-full"
@click.stop="isCollapsed = !isCollapsed"
>
<RouterLink
:to="$view({ name: props.to })"
:class="classes"
class="flex items-center justify-between flex-1"
@click="closeSidebar"
>
<div class="flex items-center">
<GoogleIcon v-if="icon" :name="icon" class="text-xl mr-2" />
<span class="text-sm font-medium">{{ name }}</span>
</div>
<GoogleIcon
:name="isCollapsed ? 'expand_more' : 'expand_less'"
class="text-gray-400 text-lg"
/>
</RouterLink>
</button>
</div>
</li>
<div
class="transition-all duration-300 ease-in-out overflow-hidden"
:class="{ 'max-h-0': isCollapsed, 'max-h-96': !isCollapsed }"
>
<slot />
</div>
</ul>
</template>

View File

@ -1,19 +1,19 @@
<script setup> <script setup>
/** Propiedades */ /** Propiedades */
const props = defineProps({ const props = defineProps({
name: String name: String,
}); });
</script> </script>
<template> <template>
<ul v-if="$slots['default']"> <ul v-if="$slots['default']">
<li class="px-5 hidden md:block"> <li class="px-5 hidden md:block">
<div class="flex flex-row items-center h-8"> <div class="flex flex-row items-center h-8 cursor-pointer">
<div class="text-sm font-light tracking-wide text-gray-400 uppercase"> <div class="text-sm font-light tracking-wide text-gray-400 uppercase">
{{name}} {{ name }}
</div> </div>
</div> </div>
</li> </li>
<slot /> <slot />
</ul> </ul>
</template> </template>

View File

@ -6,6 +6,7 @@ import { hasPermission } from '@Plugins/RolePermission';
import Layout from '@Holos/Layout/App.vue'; import Layout from '@Holos/Layout/App.vue';
import Link from '@Holos/Skeleton/Sidebar/Link.vue'; import Link from '@Holos/Skeleton/Sidebar/Link.vue';
import Section from '@Holos/Skeleton/Sidebar/Section.vue'; import Section from '@Holos/Skeleton/Sidebar/Section.vue';
import DropDown from '@Holos/Skeleton/Sidebar/Drop.vue'
/** Definidores */ /** Definidores */
const loader = useLoader() const loader = useLoader()
@ -30,79 +31,85 @@ onMounted(() => {
<template #leftSidebar> <template #leftSidebar>
<Section name="Principal"> <Section name="Principal">
<Link <Link
icon="grid_view" icon="grid_view"
name="Dashboard" name="Dashboard"
to="admin.dashboard.index" to="admin.dashboard.index"
/> />
<Link <DropDown
icon="people" icon="people"
name="Empleados" name="Empleados"
to="admin.employees.index" to="admin.employees.index"
/> :collapsed="true"
<Link >
icon="school" <Link
name="Historial Académico" icon="school"
to="admin.academic.index" name="Historial Académico"
/> to="admin.academic.index"
<Link />
icon="security" <Link
name="Seguridad y Salud" icon="security"
to="admin.security.index" name="Seguridad y Salud"
/> to="admin.security.index"
<Link />
icon="payments" <Link
name="Nómina" icon="payments"
to="admin.payroll.index" name="Nómina"
/> to="admin.payroll.index"
<Link />
icon="info" <Link
name="Información Adicional" icon="info"
to="admin.additional.index" name="Información Adicional"
/> to="admin.additional.index"
/>
</DropDown>
</Section> </Section>
<Section name="Capacitaciones"> <Section name="Capacitaciones">
<Link <DropDown
icon="grid_view"
name="Solicitud de Cursos"
to="admin.courses.request"
/>
<Link
icon="grid_view" icon="grid_view"
name="Cursos" name="Cursos"
to="admin.courses.index" to="admin.courses.index"
/> :collapsed="true"
<Link >
icon="grid_view" <Link
name="Asignación de Cursos" icon="grid_view"
to="admin.courses.assignamment" name="Solicitud de Cursos"
/> to="admin.courses.request"
<Link />
icon="grid_view" <Link
name="Calendario de Cursos" icon="grid_view"
to="admin.courses.calendar" name="Asignación de Cursos"
/> to="admin.courses.assignamment"
/>
<Link
icon="grid_view"
name="Calendario de Cursos"
to="admin.courses.calendar"
/>
</DropDown>
</Section> </Section>
<Section name="Eventos"> <Section name="Eventos">
<Link <DropDown
icon="grid_view" icon="grid_view"
name="Dashboard" name="Eventos"
to="admin.events.index" to="admin.events.index"
/> :collapsed="true"
<Link >
icon="grid_view" <Link
name="Asignación de presupuesto" icon="grid_view"
to="admin.events.assignamment" name="Asignación de presupuesto"
/> to="admin.events.assignamment"
<Link />
icon="grid_view" <Link
name="Justificación de gastos" icon="grid_view"
to="admin.events.justification" name="Justificación de gastos"
/> to="admin.events.justification"
<Link />
icon="grid_view" <Link
name="Reportes de gastos" icon="grid_view"
to="admin.events.reports" name="Reportes de gastos"
/> to="admin.events.reports"
/>
</DropDown>
</Section> </Section>
<Section <Section
v-if="hasPermission('users.index')" v-if="hasPermission('users.index')"

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue'; import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script> </script>
<template> <template>
@ -12,13 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</div> </div>
<div> <div>
<button class="inline-flex items-center gap-3 bg-[#2563eb] hover:bg-[#1e40af] text-white px-4 py-2 rounded-full shadow-md"> <Adding text="Agregar Registro" />
<GoogleIcon
class="text-white text-xl"
name="add"
/>
Agregar Registro
</button>
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue'; import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script> </script>
<template> <template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</div> </div>
<div> <div>
<button class="inline-flex items-center gap-3 bg-[#2563eb] hover:bg-[#1e40af] text-white px-4 py-2 rounded-full shadow-md"> <Adding text="Nueva Evaluación" />
<GoogleIcon class="text-white text-xl" name="add" />
Nueva Evaluación
</button>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
<script setup> <script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue'; import GoogleIcon from '@Shared/GoogleIcon.vue';
import Searcher from '@Holos/Searcher.vue'; import Searcher from '@Holos/Searcher.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script> </script>
<template> <template>
@ -12,15 +13,8 @@ import Searcher from '@Holos/Searcher.vue';
<p class="mt-1 text-sm text-gray-500 dark:text-primary-dt/70">Gestión de información general de empleados</p> <p class="mt-1 text-sm text-gray-500 dark:text-primary-dt/70">Gestión de información general de empleados</p>
</div> </div>
<div class="flex items-center"> <div>
<button <Adding text="Nuevo Empleado" />
class="inline-flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md shadow-md"
>
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
</svg>
Nuevo Empleado
</button>
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue'; import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script> </script>
<template> <template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</div> </div>
<div> <div>
<button class="inline-flex items-center gap-3 bg-[#2563eb] hover:bg-[#1e40af] text-white px-4 py-2 rounded-full shadow-md"> <Adding text="Procesar Nómina" />
<GoogleIcon class="text-white text-xl" name="add" />
Procesar Nómina
</button>
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue'; import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script> </script>
<template> <template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</div> </div>
<div> <div>
<button class="inline-flex items-center gap-3 bg-[#2563eb] hover:bg-[#1e40af] text-white px-4 py-2 rounded-full shadow-md"> <Adding text="Agregar Información" />
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 4v16M20 12H4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
Actualizar Información
</button>
</div> </div>
</div> </div>

View File

@ -95,24 +95,16 @@ const router = createRouter({
title: 'Inicio', title: 'Inicio',
icon: 'home', icon: 'home',
}, },
redirect: '/admin/dashboard', redirect: '/admin/employees',
children: [ children: [
{ {
path: 'dashboard', path: 'dashboard',
name: 'admin.dashboard', name: 'admin.dashboard.index',
component: () => import('@Pages/Dashboard/Admin.vue'),
meta: { meta: {
title: 'Dashboard', title: 'Dashboard',
icon: 'grid_view', icon: 'grid_view',
}, },
redirect: '/admin/dashboard', component: () => import('@Pages/Dashboard/Admin.vue'),
children: [
{
path: '',
name: 'admin.dashboard.index',
component: () => import('@Pages/Dashboard/Admin.vue'),
}
]
}, },
{ {
path: 'employees', path: 'employees',
@ -127,71 +119,27 @@ const router = createRouter({
path: '', path: '',
name: 'admin.employees.index', name: 'admin.employees.index',
component: () => import('@Pages/Employees/Index.vue'), component: () => import('@Pages/Employees/Index.vue'),
} },
]
},
{
path: 'academic',
name: 'admin.academic',
meta: {
title: 'Historial Académico',
icon: 'school',
},
redirect: '/admin/academic',
children: [
{ {
path: '', path: 'academic',
name: 'admin.academic.index', name: 'admin.academic.index',
component: () => import('@Pages/Academic/Index.vue'), component: () => import('@Pages/Academic/Index.vue'),
} },
]
},
{
path: 'security',
name: 'admin.security',
meta: {
title: 'Seguridad y Salud',
icon: 'security',
},
redirect: '/admin/security',
children: [
{ {
path: '', path: 'security',
name: 'admin.security.index', name: 'admin.security.index',
component: () => import('@Pages/Security/Index.vue'), component: () => import('@Pages/Security/Index.vue'),
} },
]
},
{
path: 'payroll',
name: 'admin.payroll',
meta: {
title: 'Nómina',
icon: 'payments',
},
redirect: '/admin/payroll',
children: [
{ {
path: '', path: 'payroll',
name: 'admin.payroll.index', name: 'admin.payroll.index',
component: () => import('@Pages/Payroll/Index.vue'), component: () => import('@Pages/Payroll/Index.vue'),
} },
]
},
{
path: 'additional',
name: 'admin.additional',
meta: {
title: 'Información Adicional',
icon: 'info',
},
redirect: '/admin/additional',
children: [
{ {
path: '', path: 'additional',
name: 'admin.additional.index', name: 'admin.additional.index',
component: () => import('@Pages/Additional/Index.vue'), component: () => import('@Pages/Additional/Index.vue'),
} },
] ]
}, },
{ {