5: Implementar Plantilla AdminLTE

 

 5: Implementar Plantilla AdminLTE

1. Introducción

En este tutorial implementaremos la plantilla AdminLTE en nuestro proyecto Laravel. AdminLTE es un panel de administración gratuito y de código abierto basado en Bootstrap que nos dará una interfaz profesional y moderna para nuestro sistema de citas médicas.


2. ¿Qué es AdminLTE?

AdminLTE es una plantilla de administración que ofrece:

  • ✅ Diseño responsive (adaptable a dispositivos móviles)

  • ✅ Componentes preconstruidos (menús, tarjetas, tablas, formularios)

  • ✅ Integración con Bootstrap y Font Awesome

  • ✅ Múltiples layouts y estilos

  • ✅ Plugins incluidos (DataTables, Select2, Chart.js, etc.)


3. Descargar AdminLTE

Opción 1: Desde el repositorio (Recomendado)

Descarga la versión 2.4.2 desde:

Opción 2: Usar los archivos proporcionados

En los recursos del curso encontrarás la carpeta adminlte-2.4.2 lista para usar.


4. Estructura de AdminLTE

Al descomprimir AdminLTE, encontrarás esta estructura:

text
adminlte-2.4.2/
├── dist/               # Archivos compilados (CSS, JS)
│   ├── css/
│   │   ├── AdminLTE.css
│   │   ├── AdminLTE.min.css
│   │   └── skins/
│   └── js/
│       ├── adminlte.js
│       └── adminlte.min.js
├── bower_components/   # Dependencias (Bootstrap, jQuery, etc.)
│   ├── bootstrap/
│   ├── font-awesome/
│   ├── jQuery/
│   └── ...
├── pages/              # Ejemplos de páginas
├── index.html          # Página de inicio de ejemplo
└── ...

5. Copiar los Archivos al Proyecto

Paso 1: Abrir las carpetas

  1. Abre la carpeta de AdminLTE descargada

  2. Abre la carpeta de tu proyecto Laravel: clinica-l8

Paso 2: Copiar dist y bower_components

Copia las carpetas dist y bower_components desde AdminLTE a la carpeta public de tu proyecto:

text
📁 clinica-l8/
   └── 📁 public/
       ├── 📁 dist/          ← Copiado desde AdminLTE
       ├── 📁 bower_components/ ← Copiado desde AdminLTE
       ├── 📁 css/
       ├── 📁 js/
       └── index.php

Ruta final:

text
C:\xampp\htdocs\clinica-l8\public\dist\
C:\xampp\htdocs\clinica-l8\public\bower_components\

6. Crear la Vista Base con AdminLTE

Paso 1: Crear la carpeta de layouts

En resources/views/, crea una carpeta llamada layouts:

text
📁 resources/
   └── 📁 views/
       ├── 📁 layouts/      ← Carpeta creada
       ├── 📁 auth/
       └── ...

Paso 2: Crear el archivo app.blade.php

Crea el archivo resources/views/layouts/app.blade.php con el siguiente contenido:

html
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>@yield('title', 'Clínica L8') - Sistema de Citas Médicas</title>

    <!-- Google Font: Source Sans Pro -->
    <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">

    <!-- ============================================ -->
    <!--              ADMINLTE CSS                     -->
    <!-- ============================================ -->
    
    <!-- Bootstrap 3.3.7 -->
    <link rel="stylesheet" href="{{ asset('bower_components/bootstrap/dist/css/bootstrap.min.css') }}">
    
    <!-- Font Awesome -->
    <link rel="stylesheet" href="{{ asset('bower_components/font-awesome/css/font-awesome.min.css') }}">
    
    <!-- Ionicons -->
    <link rel="stylesheet" href="{{ asset('bower_components/Ionicons/css/ionicons.min.css') }}">
    
    <!-- Theme style -->
    <link rel="stylesheet" href="{{ asset('dist/css/AdminLTE.min.css') }}">
    
    <!-- AdminLTE Skins -->
    <link rel="stylesheet" href="{{ asset('dist/css/skins/_all-skins.min.css') }}">

    <!-- ============================================ -->
    <!--           HOJAS DE ESTILO PERSONALIZADAS     -->
    <!-- ============================================ -->
    @stack('styles')
</head>
<body class="hold-transition skin-blue sidebar-mini">
    <div class="wrapper">

        <!-- ========================================== -->
        <!--             HEADER (Navbar)                -->
        <!-- ========================================== -->
        <header class="main-header">
            <!-- Logo -->
            <a href="{{ url('/') }}" class="logo">
                <!-- mini logo para sidebar mini 50x50 px -->
                <span class="logo-mini"><b>C</b>L</span>
                <!-- logo para estado normal -->
                <span class="logo-lg"><b>Clínica</b> L8</span>
            </a>
            <!-- Header Navbar -->
            <nav class="navbar navbar-static-top" role="navigation">
                <!-- Sidebar toggle button -->
                <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
                    <span class="sr-only">Toggle navigation</span>
                </a>
                <!-- Navbar Right Menu -->
                <div class="navbar-custom-menu">
                    <ul class="nav navbar-nav">
                        <!-- User Account Menu -->
                        <li class="dropdown user user-menu">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                                <img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="user-image" alt="User Image">
                                <span class="hidden-xs">{{ Auth::user()->name ?? 'Usuario' }}</span>
                            </a>
                            <ul class="dropdown-menu">
                                <!-- User image -->
                                <li class="user-header">
                                    <img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image">
                                    <p>
                                        {{ Auth::user()->name ?? 'Usuario' }}
                                        <small>{{ Auth::user()->rol ?? 'Sin rol' }}</small>
                                    </p>
                                </li>
                                <!-- Menu Footer -->
                                <li class="user-footer">
                                    <div class="pull-left">
                                        <a href="#" class="btn btn-default btn-flat">Perfil</a>
                                    </div>
                                    <div class="pull-right">
                                        <a href="{{ route('logout') }}" class="btn btn-default btn-flat"
                                           onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
                                            Cerrar Sesión
                                        </a>
                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            @csrf
                                        </form>
                                    </div>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>
            </nav>
        </header>

        <!-- ========================================== -->
        <!--             SIDEBAR (Menú)                -->
        <!-- ========================================== -->
        <aside class="main-sidebar">
            <!-- sidebar: style can be found in sidebar.less -->
            <section class="sidebar">
                <!-- Sidebar user panel -->
                <div class="user-panel">
                    <div class="pull-left image">
                        <img src="{{ asset('dist/img/user2-160x160.jpg') }}" class="img-circle" alt="User Image">
                    </div>
                    <div class="pull-left info">
                        <p>{{ Auth::user()->name ?? 'Usuario' }}</p>
                        <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                    </div>
                </div>
                <!-- search form -->
                <form action="#" method="get" class="sidebar-form">
                    <div class="input-group">
                        <input type="text" name="q" class="form-control" placeholder="Buscar...">
                        <span class="input-group-btn">
                            <button type="submit" name="search" id="search-btn" class="btn btn-flat">
                                <i class="fa fa-search"></i>
                            </button>
                        </span>
                    </div>
                </form>
                <!-- /.search form -->

                <!-- Sidebar Menu -->
                <ul class="sidebar-menu" data-widget="tree">
                    <li class="header">MENÚ PRINCIPAL</li>
                    
                    <!-- Dashboard -->
                    <li class="@yield('active-dashboard', '')">
                        <a href="{{ url('/home') }}">
                            <i class="fa fa-dashboard"></i> <span>Dashboard</span>
                        </a>
                    </li>

                    <!-- ========================================== -->
                    <!--           MENÚ POR ROL DE USUARIO         -->
                    <!-- ========================================== -->
                    
                    @auth
                        @if(Auth::user()->rol == 'admin')
                            <!-- Administrador -->
                            <li class="header">ADMINISTRACIÓN</li>
                            <li class="@yield('active-config', '')">
                                <a href="#">
                                    <i class="fa fa-cogs"></i> <span>Configuración</span>
                                </a>
                            </li>
                        @endif

                        @if(in_array(Auth::user()->rol, ['admin', 'secretaria']))
                            <!-- Secretaria / Admin -->
                            <li class="header">GESTIÓN</li>
                            <li class="@yield('active-consultorios', '')">
                                <a href="#">
                                    <i class="fa fa-building"></i> <span>Consultorios</span>
                                </a>
                            </li>
                            <li class="@yield('active-doctores', '')">
                                <a href="#">
                                    <i class="fa fa-user-md"></i> <span>Doctores</span>
                                </a>
                            </li>
                            <li class="@yield('active-pacientes', '')">
                                <a href="#">
                                    <i class="fa fa-users"></i> <span>Pacientes</span>
                                </a>
                            </li>
                        @endif

                        @if(in_array(Auth::user()->rol, ['admin', 'secretaria', 'doctor']))
                            <li class="header">CITAS</li>
                            <li class="@yield('active-citas', '')">
                                <a href="#">
                                    <i class="fa fa-calendar"></i> <span>Agenda de Citas</span>
                                </a>
                            </li>
                        @endif

                        @if(Auth::user()->rol == 'paciente')
                            <li class="header">PACIENTE</li>
                            <li class="@yield('active-mis-citas', '')">
                                <a href="#">
                                    <i class="fa fa-calendar-check-o"></i> <span>Mis Citas</span>
                                </a>
                            </li>
                            <li class="@yield('active-historial', '')">
                                <a href="#">
                                    <i class="fa fa-history"></i> <span>Historial</span>
                                </a>
                            </li>
                        @endif
                    @endauth
                </ul>
                <!-- /.sidebar-menu -->
            </section>
            <!-- /.sidebar -->
        </aside>

        <!-- ========================================== -->
        <!--             CONTENIDO PRINCIPAL            -->
        <!-- ========================================== -->
        <div class="content-wrapper">
            <!-- Content Header (Page header) -->
            <section class="content-header">
                <h1>
                    @yield('page-title', 'Dashboard')
                    <small>@yield('page-subtitle', 'Panel de control')</small>
                </h1>
                <ol class="breadcrumb">
                    <li><a href="{{ url('/home') }}"><i class="fa fa-dashboard"></i> Inicio</a></li>
                    @yield('breadcrumb')
                </ol>
            </section>

            <!-- Main content -->
            <section class="content">
                @yield('content')
            </section>
            <!-- /.content -->
        </div>
        <!-- /.content-wrapper -->

        <!-- ========================================== -->
        <!--               FOOTER                       -->
        <!-- ========================================== -->
        <footer class="main-footer">
            <div class="pull-right hidden-xs">
                <b>Versión</b> 1.0.0
            </div>
            <strong>Copyright &copy; 2024 <a href="#">Clínica L8</a>.</strong> Todos los derechos reservados.
        </footer>

    </div>
    <!-- ./wrapper -->

    <!-- ============================================ -->
    <!--            SCRIPTS DE ADMINLTE               -->
    <!-- ============================================ -->
    
    <!-- jQuery 3 -->
    <script src="{{ asset('bower_components/jquery/dist/jquery.min.js') }}"></script>
    
    <!-- Bootstrap 3.3.7 -->
    <script src="{{ asset('bower_components/bootstrap/dist/js/bootstrap.min.js') }}"></script>
    
    <!-- AdminLTE App -->
    <script src="{{ asset('dist/js/adminlte.min.js') }}"></script>

    <!-- ============================================ -->
    <!--           SCRIPTS PERSONALIZADOS             -->
    <!-- ============================================ -->
    @stack('scripts')
</body>
</html>

7. Crear la Vista de Inicio (Home)

Paso 1: Crear el archivo home.blade.php

Crea resources/views/home.blade.php:

php
@extends('layouts.app')

@section('title', 'Dashboard')

@section('page-title', 'Dashboard')
@section('page-subtitle', 'Panel de control')

@section('content')
<div class="row">
    <div class="col-lg-3 col-xs-6">
        <!-- small box -->
        <div class="small-box bg-aqua">
            <div class="inner">
                <h3>{{ $totalDoctores ?? 0 }}</h3>
                <p>Doctores</p>
            </div>
            <div class="icon">
                <i class="fa fa-user-md"></i>
            </div>
            <a href="#" class="small-box-footer">Más info <i class="fa fa-arrow-circle-right"></i></a>
        </div>
    </div>
    <!-- ./col -->
    
    <div class="col-lg-3 col-xs-6">
        <div class="small-box bg-green">
            <div class="inner">
                <h3>{{ $totalPacientes ?? 0 }}</h3>
                <p>Pacientes</p>
            </div>
            <div class="icon">
                <i class="fa fa-users"></i>
            </div>
            <a href="#" class="small-box-footer">Más info <i class="fa fa-arrow-circle-right"></i></a>
        </div>
    </div>
    <!-- ./col -->
    
    <div class="col-lg-3 col-xs-6">
        <div class="small-box bg-yellow">
            <div class="inner">
                <h3>{{ $totalCitasHoy ?? 0 }}</h3>
                <p>Citas Hoy</p>
            </div>
            <div class="icon">
                <i class="fa fa-calendar"></i>
            </div>
            <a href="#" class="small-box-footer">Más info <i class="fa fa-arrow-circle-right"></i></a>
        </div>
    </div>
    <!-- ./col -->
    
    <div class="col-lg-3 col-xs-6">
        <div class="small-box bg-red">
            <div class="inner">
                <h3>{{ $totalConsultorios ?? 0 }}</h3>
                <p>Consultorios</p>
            </div>
            <div class="icon">
                <i class="fa fa-building"></i>
            </div>
            <a href="#" class="small-box-footer">Más info <i class="fa fa-arrow-circle-right"></i></a>
        </div>
    </div>
    <!-- ./col -->
</div>
<!-- /.row -->

<div class="row">
    <div class="col-md-6">
        <div class="box box-primary">
            <div class="box-header with-border">
                <h3 class="box-title">Citas Recientes</h3>
                <div class="box-tools pull-right">
                    <button type="button" class="btn btn-box-tool" data-widget="collapse">
                        <i class="fa fa-minus"></i>
                    </button>
                </div>
            </div>
            <div class="box-body">
                <p class="text-muted">Próximamente: lista de citas recientes</p>
            </div>
        </div>
    </div>
    <div class="col-md-6">
        <div class="box box-success">
            <div class="box-header with-border">
                <h3 class="box-title">Actividad Reciente</h3>
                <div class="box-tools pull-right">
                    <button type="button" class="btn btn-box-tool" data-widget="collapse">
                        <i class="fa fa-minus"></i>
                    </button>
                </div>
            </div>
            <div class="box-body">
                <p class="text-muted">Próximamente: actividad del sistema</p>
            </div>
        </div>
    </div>
</div>
@endsection

@push('styles')
<style>
    /* Estilos personalizados si es necesario */
</style>
@endpush

@push('scripts')
<script>
    $(document).ready(function() {
        // Scripts personalizados
        console.log('Dashboard cargado correctamente');
    });
</script>
@endpush

8. Actualizar el Controlador Home

Modifica app/Http/Controllers/HomeController.php:

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Contracts\Support\Renderable
     */
    public function index()
    {
        // Datos para el dashboard (temporales)
        $data = [
            'totalDoctores' => 5,
            'totalPacientes' => 12,
            'totalCitasHoy' => 3,
            'totalConsultorios' => 4,
        ];
        
        return view('home', $data);
    }
}

9. Actualizar las Rutas

Modifica routes/web.php:

php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;

Route::get('/', function () {
    return view('auth.login');
});

Auth::routes();

Route::get('/home', [HomeController::class, 'index'])->name('home');

10. Verificar la Implementación

Paso 1: Iniciar el servidor

bash
php artisan serve

Paso 2: Iniciar sesión

Ve a http://127.0.0.1:8000/login e inicia sesión con tu usuario administrador.

Paso 3: Ver el resultado

Deberías ver el dashboard con la plantilla AdminLTE completamente implementada:

text
┌─────────────────────────────────────────────────────────────┐
│  [Logo] Clínica L8                    [Usuario ▼] [Logout]  │
├─────────────────────────────────────────────────────────────┤
│  ☰  Dashboard                                             │
│    Menú Principal                                          │
│      Dashboard                                             │
│    ADMINISTRACIÓN                                          │
│      Configuración                                         │
│    GESTIÓN                                                 │
│      Consultorios                                          │
│      Doctores                                              │
│      Pacientes                                             │
│    CITAS                                                   │
│      Agenda de Citas                                       │
├─────────────────────────────────────────────────────────────┤
│  1  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│      │ Doctores │  │Pacientes│  │Citas Hoy│  │Consultor│   │
│      │    5     │  │   12    │  │    3    │  │    4    │   │
│      └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
│                                                             │
│  2  ┌──────────────────┐  ┌──────────────────┐            │
│      │  Citas Recientes │  │ Actividad Reciente│            │
│      │  ...             │  │  ...             │            │
│      └──────────────────┘  └──────────────────┘            │
│                                                             │
│  Copyright © 2024 Clínica L8. Todos los derechos reservados.│
└─────────────────────────────────────────────────────────────┘

11. Resumen de Archivos Creados/Modificados

ArchivoAcción
public/dist/Copiar desde AdminLTE
public/bower_components/Copiar desde AdminLTE
resources/views/layouts/app.blade.phpCrear (layout principal)
resources/views/home.blade.phpCrear (dashboard)
app/Http/Controllers/HomeController.phpModificar
routes/web.phpModificar

12. Solución de Problemas

ProblemaSolución
No se ven los estilosVerifica que las rutas de asset() sean correctas
Error 404 en archivos CSS/JSVerifica que dist y bower_components estén en public/
Font Awesome no cargaVerifica la carpeta bower_components/font-awesome/
Menú no se colapsaAsegura que jQuery y bootstrap.js estén cargados
Error Undefined variable en homePasa datos al controlador o usa valores por defecto

13. Conclusión

🎉 ¡Excelente trabajo! Hemos implementado correctamente AdminLTE en nuestro proyecto Laravel. Ahora tenemos:

  • ✅ Un diseño profesional y responsive

  • ✅ Menú dinámico según el rol del usuario

  • ✅ Dashboard con indicadores

  • ✅ Estructura base para desarrollar los módulos del sistema

En el próximo tutorial comenzaremos a desarrollar el módulo de secretaria, empezando por la gestión de consultorios.

Comentarios