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:
Busca el archivo
adminlte-2.4.2.zip
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:
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
Abre la carpeta de AdminLTE descargada
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:
📁 clinica-l8/
└── 📁 public/
├── 📁 dist/ ← Copiado desde AdminLTE
├── 📁 bower_components/ ← Copiado desde AdminLTE
├── 📁 css/
├── 📁 js/
└── index.phpRuta final:
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:
📁 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:
<!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 © 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:
@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>
@endpush8. Actualizar el Controlador Home
Modifica app/Http/Controllers/HomeController.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
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
php artisan servePaso 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:
┌─────────────────────────────────────────────────────────────┐
│ [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
| Archivo | Acción |
|---|---|
public/dist/ | Copiar desde AdminLTE |
public/bower_components/ | Copiar desde AdminLTE |
resources/views/layouts/app.blade.php | Crear (layout principal) |
resources/views/home.blade.php | Crear (dashboard) |
app/Http/Controllers/HomeController.php | Modificar |
routes/web.php | Modificar |
12. Solución de Problemas
| Problema | Solución |
|---|---|
| No se ven los estilos | Verifica que las rutas de asset() sean correctas |
| Error 404 en archivos CSS/JS | Verifica que dist y bower_components estén en public/ |
| Font Awesome no carga | Verifica la carpeta bower_components/font-awesome/ |
| Menú no se colapsa | Asegura que jQuery y bootstrap.js estén cargados |
Error Undefined variable en home | Pasa 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
Publicar un comentario