You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1270 lines
28 KiB
Vue

<!-- components/AdminAcademia/layout/AdminLayout.vue -->
<template>
<a-layout style="min-height: 100vh;" class="admin-layout">
<!-- Header Responsive -->
<a-layout-header class="header">
<div class="header-container">
<div class="header-left">
<div class="brand-section">
<a-button
type="text"
class="menu-toggle"
@click="toggleSidebar"
>
<MenuOutlined />
</a-button>
<router-link to="/admin/dashboard" class="logo-wrapper">
<div class="logo-content">
<h1 class="admin-name">Dirección de Admisión</h1>
</div>
</router-link>
</div>
</div>
<!-- Desktop Actions -->
<div class="header-right">
<!-- Perfil -->
<a-dropdown :trigger="['click']" placement="bottomRight" class="profile-dropdown-wrapper">
<div class="profile-trigger">
<div class="profile-info">
<a-avatar
:size="isMobile ? 32 : 36"
class="profile-avatar"
:style="{ background: getAvatarColor(userStore.user?.name) }"
>
{{ getUserInitials(userStore.user?.name) }}
</a-avatar>
<div class="profile-details" v-if="!isMobile">
<div class="profile-name">{{ userStore.user?.name || 'Usuario' }}</div>
<div class="role-badge-wrapper">
</div>
</div>
</div>
<DownOutlined class="dropdown-chevron" />
</div>
<template #overlay>
<div class="profile-dropdown">
<div class="profile-summary">
<a-avatar
:size="48"
:style="{ background: getAvatarColor(userStore.user?.name) }"
>
{{ getUserInitials(userStore.user?.name) }}
</a-avatar>
<div class="profile-summary-info">
<div class="profile-name">{{ userStore.user?.name || 'Usuario' }}</div>
<div class="profile-email">{{ userStore.user?.email || 'email@ejemplo.com' }}</div>
<div class="profile-role-tag" :class="getRoleClass(userStore.user?.roles?.[0])">
{{ formatRole(userStore.user?.roles?.[0]) || 'Administrador' }}
</div>
</div>
</div>
<div class="dropdown-item" @click="irPerfil">
<UserOutlined class="dropdown-icon" />
<div class="dropdown-item-content">
<div class="dropdown-item-title">Mi Perfil</div>
<div class="dropdown-item-subtitle">Configura tu cuenta</div>
</div>
</div>
<div class="dropdown-item" @click="irConfiguracion">
<SettingOutlined class="dropdown-icon" />
<div class="dropdown-item-content">
<div class="dropdown-item-title">Configuración</div>
<div class="dropdown-item-subtitle">Ajustes del sistema</div>
</div>
</div>
<div class="dropdown-divider" />
<div class="dropdown-item logout" @click="logout">
<LogoutOutlined class="dropdown-icon" />
<div class="dropdown-item-content">
<div class="dropdown-item-title">Cerrar sesión</div>
<div class="dropdown-item-subtitle">Salir del sistema</div>
</div>
</div>
</div>
</template>
</a-dropdown>
</div>
</div>
</a-layout-header>
<!-- Layout Principal Responsive -->
<a-layout
class="main-layout"
:class="{
'layout-collapsed': sidebarCollapsed && !isMobile
}"
>
<!-- Sidebar - Visible en desktop, oculto en móvil -->
<div
v-if="isMobile && !sidebarCollapsed"
class="sidebar-backdrop"
@click="sidebarCollapsed = true"
/>
<a-layout-sider
v-model:collapsed="sidebarCollapsed"
:width="sidebarWidth"
:collapsedWidth="collapsedWidth"
collapsible
breakpoint="lg"
:trigger="null"
theme="light"
class="sidebar"
:class="{ 'sidebar-collapsed': sidebarCollapsed, 'sidebar-mobile': isMobile }"
@breakpoint="onBreakpoint"
>
<div class="sidebar-menu-container">
<a-menu
v-model:selectedKeys="selectedKeys"
mode="inline"
class="sidebar-menu"
@select="handleMenuSelect"
>
<!-- Dashboard -->
<a-menu-item key="dashboard" class="menu-item">
<div class="menu-item-content">
<DashboardOutlined class="menu-icon" />
<span class="menu-label">Dashboard</span>
</div>
</a-menu-item>
<!-- Gestión Académica -->
<div class="menu-section" v-if="!sidebarCollapsed">
<div class="section-label">Gestión Académica</div>
</div>
<a-sub-menu key="estudiantes" class="sub-menu">
<template #title>
<div class="sub-menu-title">
<TeamOutlined class="menu-icon" />
<span class="menu-label">Estudiantes</span>
<span class="menu-badge" v-if="!sidebarCollapsed">24</span>
</div>
</template>
<a-menu-item key="estudiantes-lista" class="menu-item">
<div class="menu-item-content">
<UnorderedListOutlined class="menu-icon" />
<span class="menu-label">Lista</span>
</div>
</a-menu-item>
<a-menu-item key="estudiantes-nuevo" class="menu-item">
<div class="menu-item-content">
<UserAddOutlined class="menu-icon" />
<span class="menu-label">Agregar</span>
</div>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="examenes" class="sub-menu">
<template #title>
<div class="sub-menu-title">
<FileTextOutlined class="menu-icon" />
<span class="menu-label">Exámenes</span>
<span class="menu-badge" v-if="!sidebarCollapsed">5</span>
</div>
</template>
<a-menu-item key="examenes-proceso-lista" class="menu-item">
<div class="menu-item-content">
<UnorderedListOutlined class="menu-icon" />
<span class="menu-label">Procesos</span>
</div>
</a-menu-item>
<a-menu-item key="examenes-area-lista" class="menu-item">
<div class="menu-item-content">
<UnorderedListOutlined class="menu-icon" />
<span class="menu-label">Areas</span>
</div>
</a-menu-item>
<a-menu-item key="examenes-curso-lista" class="menu-item">
<div class="menu-item-content">
<UnorderedListOutlined class="menu-icon" />
<span class="menu-label">Cursos</span>
</div>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="preguntas" class="sub-menu">
<template #title>
<div class="sub-menu-title">
<QuestionCircleOutlined class="menu-icon" />
<span class="menu-label">Preguntas</span>
</div>
</template>
<a-menu-item key="lista-areas" class="menu-item">
<div class="menu-item-content">
<AppstoreOutlined class="menu-icon" />
<span class="menu-label">Áreas</span>
</div>
</a-menu-item>
<a-menu-item key="lista-cursos" class="menu-item">
<div class="menu-item-content">
<BookOutlined class="menu-icon" />
<span class="menu-label">Cursos</span>
</div>
</a-menu-item>
</a-sub-menu>
<!-- Análisis -->
<div class="menu-section" v-if="!sidebarCollapsed">
<div class="section-label">Análisis</div>
</div>
<a-menu-item key="resultados" class="menu-item">
<div class="menu-item-content">
<RiseOutlined class="menu-icon" />
<span class="menu-label">Resultados</span>
</div>
</a-menu-item>
<a-menu-item key="reportes" class="menu-item">
<div class="menu-item-content">
<BarChartOutlined class="menu-icon" />
<span class="menu-label">Reportes</span>
<span class="menu-badge new" v-if="!sidebarCollapsed">Nuevo</span>
</div>
</a-menu-item>
<!-- Administración -->
<div class="menu-section" v-if="!sidebarCollapsed">
<div class="section-label">Administración</div>
</div>
<a-menu-item key="config-academia" class="menu-item">
<div class="menu-item-content">
<SettingOutlined class="menu-icon" />
<span class="menu-label">Configuración</span>
</div>
</a-menu-item>
<a-menu-item key="usuarios" class="menu-item">
<div class="menu-item-content">
<SafetyOutlined class="menu-icon" />
<span class="menu-label">Usuarios</span>
</div>
</a-menu-item>
</a-menu>
</div>
<!-- Footer del Sidebar -->
<div class="sidebar-footer" v-if="!sidebarCollapsed">
<div class="sidebar-help" @click="openHelp">
<QuestionCircleOutlined />
<span>Centro de Ayuda</span>
</div>
<div class="sidebar-version">
<div class="version">v2.1.0</div>
<div class="last-update">Actualizado hoy</div>
</div>
</div>
</a-layout-sider>
<!-- Contenido Principal -->
<a-layout-content class="content" :class="{ 'content-collapsed': sidebarCollapsed && !isMobile }">
<div class="content-container">
<!-- Breadcrumb y Acciones -->
<div class="content-header">
<div class="breadcrumb">
<a-breadcrumb separator=">">
<a-breadcrumb-item>
<HomeOutlined />
</a-breadcrumb-item>
<a-breadcrumb-item>{{ currentSection }}</a-breadcrumb-item>
<a-breadcrumb-item v-if="currentSubSection">{{ currentSubSection }}</a-breadcrumb-item>
</a-breadcrumb>
</div>
</div>
<!-- Contenido Dinámico -->
<div class="content-wrapper">
<a-card class="content-card">
<router-view />
</a-card>
</div>
</div>
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useUserStore } from '../../../store/user'
import {
DownOutlined,
UserOutlined,
SettingOutlined,
LogoutOutlined,
DashboardOutlined,
TeamOutlined,
FileTextOutlined,
RiseOutlined,
BarChartOutlined,
MenuOutlined,
PlusOutlined,
UnorderedListOutlined,
QuestionCircleOutlined,
AppstoreOutlined,
BookOutlined,
UserAddOutlined,
SafetyOutlined,
ExportOutlined,
HomeOutlined,
} from '@ant-design/icons-vue'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
// Estado
const selectedKeys = ref(['dashboard'])
const sidebarCollapsed = ref(false)
const isMobile = ref(false)
const currentSection = ref('Dashboard')
const currentSubSection = ref('')
const pageTitle = ref('Dashboard')
const pageSubtitle = ref('Resumen general del sistema')
// Computed
const sidebarWidth = computed(() => 280)
const collapsedWidth = computed(() => (isMobile.value ? 0 : 80))
// Métodos
const checkMobile = () => {
isMobile.value = window.innerWidth < 992
if (isMobile.value) {
sidebarCollapsed.value = true
}
}
const toggleSidebar = () => {
if (isMobile.value) {
sidebarCollapsed.value = !sidebarCollapsed.value
} else {
sidebarCollapsed.value = !sidebarCollapsed.value
}
}
const onBreakpoint = (broken) => {
isMobile.value = broken
if (broken) {
sidebarCollapsed.value = true
}
}
const getUserInitials = (name) => {
if (!name) return 'U'
const parts = name.split(' ')
if (parts.length === 1) return parts[0].charAt(0).toUpperCase()
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase()
}
const getAvatarColor = (name) => {
if (!name) return '#1890ff'
const colors = [
'#1890ff', '#52c41a', '#fa8c16', '#f5222d',
'#722ed1', '#13c2c2', '#eb2f96', '#faad14'
]
const index = name.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
return colors[index % colors.length]
}
const formatRole = (role) => {
if (!role) return 'Administrador'
const roleMap = {
'admin': 'Administrador',
'super_admin': 'Super Admin',
'editor': 'Editor',
'viewer': 'Visualizador'
}
return roleMap[role.toLowerCase()] || role
}
const getRoleClass = (role) => {
if (!role) return 'role-admin'
const roleClassMap = {
'admin': 'role-admin',
'super_admin': 'role-super-admin',
'editor': 'role-editor',
'viewer': 'role-viewer'
}
return roleClassMap[role.toLowerCase()] || 'role-default'
}
const handleMenuSelect = ({ key }) => {
selectedKeys.value = [key]
updatePageInfo(key)
const routes = {
'dashboard': { name: 'Dashboard' },
'estudiantes-lista': { name: 'AcademiaEstudiantes' },
'estudiantes-nuevo': { name: 'AcademiaEstudianteNuevo' },
'examenes-proceso-lista': { name: 'Procesos' },
'examenes-area-lista': { name: 'Areas' },
'examenes-curso-lista': { name: 'Cursos' },
'lista-areas': { name: 'AcademiaAreas' },
'lista-cursos': { name: 'AcademiaCursos' },
'resultados': { name: 'AcademiaResultados' },
'reportes': { name: 'AcademiaReportes' },
'config-academia': { name: 'AcademiaConfig' },
'usuarios': { name: 'AcademiaUsuarios' }
}
if (routes[key]) {
router.push(routes[key])
}
}
const updatePageInfo = (key) => {
const pageInfo = {
'dashboard': {
section: 'Dashboard',
subSection: '',
title: 'Dashboard',
subtitle: 'Resumen general del sistema'
},
'estudiantes-lista': {
section: 'Estudiantes',
subSection: 'Lista',
title: 'Estudiantes',
subtitle: 'Gestión de estudiantes registrados'
},
'estudiantes-nuevo': {
section: 'Estudiantes',
subSection: 'Nuevo',
title: 'Nuevo Estudiante',
subtitle: 'Agregar nuevo estudiante al sistema'
},
'examenes-proceso-lista': {
section: 'Exámenes',
subSection: 'Procesos',
title: 'Exámenes',
subtitle: 'Lista de Procesos'
},
'examenes-area-lista': {
section: 'Exámenes',
subSection: 'Areas',
title: 'Exámenes',
subtitle: 'Lista de Areas'
},
'examenes-curso-lista': {
section: 'Exámenes',
subSection: 'cursos',
title: 'cursos',
subtitle: 'Lista de Cursos'
}
}
const info = pageInfo[key] || {
section: key,
subSection: '',
title: key.charAt(0).toUpperCase() + key.slice(1),
subtitle: ''
}
currentSection.value = info.section
currentSubSection.value = info.subSection
pageTitle.value = info.title
pageSubtitle.value = info.subtitle
}
const logout = () => {
userStore.logout()
router.push('/login')
}
const irPerfil = () => {
router.push({ name: 'PerfilUsuario' })
}
const irConfiguracion = () => {
router.push({ name: 'AcademiaConfig' })
}
const openHelp = () => {
window.open('/ayuda', '_blank')
}
// Lifecycle
onMounted(() => {
checkMobile()
window.addEventListener('resize', checkMobile)
updatePageInfo(selectedKeys.value[0])
})
onUnmounted(() => {
window.removeEventListener('resize', checkMobile)
})
// Watch route changes
watch(() => route.name, () => {
const routeKeyMap = {
'AcademiaDashboard': 'dashboard',
'AcademiaEstudiantes': 'estudiantes-lista',
'AcademiaExamenes': 'examenes-lista',
'AcademiaReportes': 'reportes',
'AcademiaConfig': 'config-academia'
}
const key = routeKeyMap[route.name] || 'dashboard'
selectedKeys.value = [key]
updatePageInfo(key)
})
</script>
<style scoped>
/* Layout General */
.admin-layout {
background: #f8fafc;
}
/* Header Moderno */
.header {
background: white;
height: 64px;
padding: 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border-bottom: 1px solid #f0f0f0;
position: sticky;
top: 0;
z-index: 100;
}
.header-container {
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
}
.header-left {
display: flex;
align-items: center;
gap: 16px;
}
.brand-section {
display: flex;
align-items: center;
gap: 16px;
}
.menu-toggle {
width: 40px;
height: 40px;
border-radius: 8px;
border: none;
color: #666;
font-size: 18px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
}
.menu-toggle:hover {
background: #f5f5f5;
}
.logo-wrapper {
display: flex;
align-items: center;
gap: 12px;
text-decoration: none;
}
.logo-content {
display: flex;
flex-direction: column;
}
.admin-name {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #1f1f1f;
line-height: 1.4;
}
/* Header Actions */
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.profile-trigger {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 8px;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s;
}
.profile-trigger:hover {
background: #f5f5f5;
}
.profile-info {
display: flex;
align-items: center;
gap: 8px;
}
.profile-avatar {
background: linear-gradient(135deg, #1890ff 0%, #52c41a 100%);
font-weight: 500;
color: white;
}
.profile-details {
display: flex;
flex-direction: column;
}
.profile-name {
font-size: 14px;
font-weight: 500;
color: #1f1f1f;
line-height: 1.4;
}
.role-badge-wrapper {
margin-top: 2px;
}
.role-badge {
font-size: 11px;
padding: 2px 6px;
border-radius: 10px;
background: #e6f7ff;
color: #1890ff;
font-weight: 500;
}
.role-badge.role-admin {
background: #e6f7ff;
color: #1890ff;
}
.role-badge.role-super-admin {
background: #f6ffed;
color: #52c41a;
}
.role-badge.role-editor {
background: #fff7e6;
color: #fa8c16;
}
.role-badge.role-viewer {
background: #f9f0ff;
color: #722ed1;
}
.dropdown-chevron {
font-size: 12px;
color: #999;
transition: transform 0.3s;
}
.profile-trigger:hover .dropdown-chevron {
color: #666;
}
/* Profile Dropdown */
.profile-dropdown {
width: 280px;
background: white;
border-radius: 12px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
overflow: hidden;
border: 1px solid #f0f0f0;
}
.profile-summary {
padding: 20px;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
display: flex;
gap: 12px;
align-items: center;
}
.profile-summary-info {
flex: 1;
}
.profile-summary-info .profile-name {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
}
.profile-email {
font-size: 12px;
color: #666;
margin-bottom: 8px;
}
.profile-role-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
}
.profile-role-tag.role-admin {
background: #1890ff;
color: white;
}
.profile-role-tag.role-super-admin {
background: #52c41a;
color: white;
}
.profile-role-tag.role-editor {
background: #fa8c16;
color: white;
}
.profile-role-tag.role-viewer {
background: #722ed1;
color: white;
}
.dropdown-item {
padding: 12px 20px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: background 0.3s;
}
.dropdown-item:hover {
background: #f5f5f5;
}
.dropdown-icon {
font-size: 16px;
color: #666;
}
.dropdown-item-content {
flex: 1;
}
.dropdown-item-title {
font-size: 14px;
font-weight: 500;
color: #1f1f1f;
margin-bottom: 2px;
}
.dropdown-item-subtitle {
font-size: 12px;
color: #999;
}
.dropdown-divider {
height: 1px;
background: #f0f0f0;
margin: 4px 0;
}
.dropdown-item.logout {
border-top: 1px solid #f0f0f0;
margin-top: 4px;
}
.dropdown-item.logout .dropdown-icon {
color: #ff4d4f;
}
.dropdown-item.logout .dropdown-item-title {
color: #ff4d4f;
}
/* Sidebar */
.sidebar {
background: white;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.06);
border-right: 1px solid #f0f0f0;
height: calc(100vh - 64px);
position: fixed;
left: 0;
top: 64px;
z-index: 99;
transition: all 0.3s;
}
.sidebar-menu-container {
height: calc(100% - 100px);
overflow-y: auto;
padding: 16px 0;
}
.sidebar-menu-container::-webkit-scrollbar {
width: 4px;
}
.sidebar-menu-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.sidebar-menu-container::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
}
.sidebar-menu {
border-right: none !important;
}
.menu-section {
padding: 0 16px;
margin: 24px 0 12px 0;
}
.menu-section:first-child {
margin-top: 0;
}
.section-label {
font-size: 11px;
color: #999;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
}
.menu-item {
border-radius: 0 !important;
margin: 0 !important;
height: 40px !important;
padding: 0 16px !important;
border-left: 3px solid transparent !important;
}
.menu-item-content {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
}
.menu-icon {
font-size: 16px;
color: #666;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.menu-label {
font-size: 14px;
color: #333;
flex: 1;
}
.menu-badge {
font-size: 11px;
padding: 2px 6px;
border-radius: 10px;
background: #f5f5f5;
color: #666;
font-weight: 500;
}
.menu-badge.new {
background: #fff7e6;
color: #fa8c16;
}
.menu-item:deep(.ant-menu-item-selected) {
background: #e6f7ff !important;
border-left-color: #1890ff !important;
}
.menu-item:deep(.ant-menu-item-selected) .menu-icon,
.menu-item:deep(.ant-menu-item-selected) .menu-label {
color: #1890ff !important;
}
.menu-item:deep(.ant-menu-item-selected) .menu-badge {
background: rgba(24, 144, 255, 0.1) !important;
color: #1890ff !important;
}
.sub-menu {
margin: 0 !important;
}
.sub-menu :deep(.ant-menu-submenu-title) {
border-radius: 0 !important;
height: 40px !important;
padding: 0 16px !important;
margin: 0 !important;
border-left: 3px solid transparent !important;
}
.sub-menu-title {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
}
.sub-menu :deep(.ant-menu-submenu-title:hover) {
background: #f5f5f5 !important;
}
.sub-menu :deep(.ant-menu-submenu-arrow) {
color: #999 !important;
}
.sub-menu :deep(.ant-menu-submenu-selected) .sub-menu-title {
color: #1890ff !important;
}
.sub-menu :deep(.ant-menu-submenu-selected) .menu-icon {
color: #1890ff !important;
}
/* Sidebar Footer */
.sidebar-footer {
padding: 16px;
border-top: 1px solid #f0f0f0;
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: white;
}
.sidebar-help {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
border-radius: 6px;
color: #666;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
}
.sidebar-help:hover {
background: #f5f5f5;
color: #1890ff;
}
.sidebar-version {
margin-top: 12px;
padding: 8px;
background: #f8fafc;
border-radius: 6px;
text-align: center;
}
.version {
font-size: 12px;
font-weight: 500;
color: #666;
}
.last-update {
font-size: 11px;
color: #999;
margin-top: 2px;
}
/* Main Layout */
.main-layout {
margin-left: 280px;
transition: margin-left 0.3s ease;
min-height: calc(100vh - 64px);
}
/* CORRECCIÓN PRINCIPAL: Cuando el sidebar está colapsado */
.main-layout.layout-collapsed {
margin-left: 80px;
}
/* Content */
.content {
background: #f8fafc;
min-height: calc(100vh - 64px);
padding: 24px;
width: 100%;
box-sizing: border-box;
}
.content-container {
max-width: 100%;
margin: 0 auto;
}
/* Content Header */
.content-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 24px;
flex-wrap: wrap;
gap: 16px;
}
.breadcrumb {
flex: 1;
min-width: 0;
}
.breadcrumb :deep(.ant-breadcrumb) {
font-size: 14px;
}
.breadcrumb :deep(.ant-breadcrumb a) {
color: #666;
}
.breadcrumb :deep(.ant-breadcrumb li:last-child a) {
color: #1f1f1f;
font-weight: 500;
}
.page-title {
margin-top: 8px;
}
.page-title h2 {
margin: 0;
font-size: 24px;
font-weight: 600;
color: #1f1f1f;
line-height: 1.3;
}
.page-subtitle {
font-size: 14px;
color: #666;
margin-top: 4px;
}
.content-actions {
display: flex;
align-items: center;
gap: 8px;
}
/* Stats Grid */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.stat-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border: 1px solid #f0f0f0;
transition: all 0.3s;
}
.stat-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.stat-content {
display: flex;
align-items: center;
gap: 16px;
}
.stat-icon-wrapper {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
.stat-info {
flex: 1;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #1f1f1f;
line-height: 1.3;
}
.stat-label {
font-size: 14px;
color: #666;
margin-top: 2px;
}
/* Content Wrapper */
.content-wrapper {
background: transparent;
}
.content-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border: 1px solid #f0f0f0;
min-height: auto;
}
/* Responsive */
@media (max-width: 992px) {
/* En móvil, el main-layout no tiene margen izquierdo */
.main-layout {
margin-left: 0 !important;
}
/* En móvil, cuando el sidebar está expandido, no debe afectar el layout */
.main-layout.layout-collapsed {
margin-left: 0 !important;
}
.sidebar {
z-index: 1000;
}
.content {
padding: 20px;
}
.header-container {
padding: 0 20px;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.header {
height: 56px;
}
.sidebar {
top: 56px;
height: calc(100vh - 56px);
}
.content {
padding: 16px;
min-height: calc(100vh - 56px);
}
.header-container {
padding: 0 16px;
}
.admin-name {
font-size: 14px;
}
.logo-icon {
width: 32px;
height: 32px;
font-size: 14px;
}
.menu-toggle {
width: 36px;
height: 36px;
font-size: 16px;
}
.page-title h2 {
font-size: 20px;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 12px;
}
.content-header {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.content-actions {
justify-content: flex-end;
}
}
@media (max-width: 576px) {
.header-container {
padding: 0 12px;
}
.content {
padding: 12px;
}
.profile-details {
display: none;
}
.dropdown-chevron {
display: none;
}
}
/* Backdrop para móvil */
.sidebar-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 998;
}
/* Sidebar en móvil */
.sidebar.sidebar-mobile {
position: fixed;
left: 0;
top: 64px;
height: calc(100vh - 64px);
z-index: 999;
transition: transform 0.3s ease;
}
.sidebar.sidebar-mobile.ant-layout-sider-collapsed {
transform: translateX(-100%);
}
</style>