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,16 +1,16 @@
<script setup>
/** Propiedades */
const props = defineProps({
name: String
name: String,
});
</script>
<template>
<ul v-if="$slots['default']">
<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">
{{name}}
{{ name }}
</div>
</div>
</li>

View File

@ -6,6 +6,7 @@ import { hasPermission } from '@Plugins/RolePermission';
import Layout from '@Holos/Layout/App.vue';
import Link from '@Holos/Skeleton/Sidebar/Link.vue';
import Section from '@Holos/Skeleton/Sidebar/Section.vue';
import DropDown from '@Holos/Skeleton/Sidebar/Drop.vue'
/** Definidores */
const loader = useLoader()
@ -34,11 +35,12 @@ onMounted(() => {
name="Dashboard"
to="admin.dashboard.index"
/>
<Link
<DropDown
icon="people"
name="Empleados"
to="admin.employees.index"
/>
:collapsed="true"
>
<Link
icon="school"
name="Historial Académico"
@ -59,18 +61,20 @@ onMounted(() => {
name="Información Adicional"
to="admin.additional.index"
/>
</DropDown>
</Section>
<Section name="Capacitaciones">
<DropDown
icon="grid_view"
name="Cursos"
to="admin.courses.index"
:collapsed="true"
>
<Link
icon="grid_view"
name="Solicitud de Cursos"
to="admin.courses.request"
/>
<Link
icon="grid_view"
name="Cursos"
to="admin.courses.index"
/>
<Link
icon="grid_view"
name="Asignación de Cursos"
@ -81,13 +85,15 @@ onMounted(() => {
name="Calendario de Cursos"
to="admin.courses.calendar"
/>
</DropDown>
</Section>
<Section name="Eventos">
<Link
<DropDown
icon="grid_view"
name="Dashboard"
name="Eventos"
to="admin.events.index"
/>
:collapsed="true"
>
<Link
icon="grid_view"
name="Asignación de presupuesto"
@ -103,6 +109,7 @@ onMounted(() => {
name="Reportes de gastos"
to="admin.events.reports"
/>
</DropDown>
</Section>
<Section
v-if="hasPermission('users.index')"

View File

@ -1,5 +1,6 @@
<script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script>
<template>
@ -12,13 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</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">
<GoogleIcon
class="text-white text-xl"
name="add"
/>
Agregar Registro
</button>
<Adding text="Agregar Registro" />
</div>
</div>

View File

@ -1,5 +1,6 @@
<script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script>
<template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</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">
<GoogleIcon class="text-white text-xl" name="add" />
Nueva Evaluación
</button>
<Adding text="Nueva Evaluación" />
</div>
</div>

View File

@ -1,6 +1,7 @@
<script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue';
import Searcher from '@Holos/Searcher.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script>
<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>
</div>
<div class="flex items-center">
<button
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>
<Adding text="Nuevo Empleado" />
</div>
</div>

View File

@ -1,5 +1,6 @@
<script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script>
<template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</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">
<GoogleIcon class="text-white text-xl" name="add" />
Procesar Nómina
</button>
<Adding text="Procesar Nómina" />
</div>
</div>

View File

@ -1,5 +1,6 @@
<script setup>
import GoogleIcon from '@Shared/GoogleIcon.vue';
import Adding from '@Holos/Button/ButtonRh.vue';
</script>
<template>
@ -12,10 +13,7 @@ import GoogleIcon from '@Shared/GoogleIcon.vue';
</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">
<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>
<Adding text="Agregar Información" />
</div>
</div>

View File

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