Livewire와 Laravel 9의 간단한 Calendario

En este tutorial, veremos como crear un calendario muy sencillo utilizando la ultima version disponible de Laravel y Livewire.

En este 튜토리얼은 라라벨의 기초를 이해하는 것입니다.

테마스 아 트라타르


  • Creación de un nuevo proyecto Laravel
  • Instalación de paquetes necesarios
  • Configuración básica de Vite

  • Proyecto 생성 및 필요한 패키지 설치



    Primeramente, creamos nuestro nuevo proyecto desde la línea de comandos;

    # Utilizamos el instalador de laravel
    laravel new calendario
    
    # Ingresamos en el directorio del proyecto
    cd calendario
    
    # Yo utilizo Valet para los proyectos
    valet link
    valet secure calendario
    
    # Intalacion del paquete Livewire
    composer require livewire/livewire
    
    # Instalacion de los paquetes NPM, 
    # primero actualizamos nuestro instalador
    npm install -g npm
    
    # Instalo los paquetes de SASS y FontAwesome
    # (opcional si no los quieres utilizar)
    npm i sass-loader sass webpack
    npm i @fortawesome/fontawesome-free
    
    # Tenemos listos los paquetenes que necesitamos
    npm install && npm run dev
    
    # Por último creamos el componente Livewire que utilizaremos
    php artisan livewire:make Calendario
    


    VITE 구성



    Con la nueva versión de Laravel, se deja de utilizar Laravel Mix, y se lo cambia por Vite, que 소개 muchas mejoras de rendimiento en tiempo de desarrollo, vamos a realizar algunos ajustes en el archivo vite.config.js, situado en la raíz del proyecto.

    Vamos a realizar tres cambios en el archivo, en primer lugar, la ubicación de los archivos CSS, ya que utilizaré SASS, por lo que renombraré esta porción de codigo en el archivo;

    // cambio el nombre del directorio por scss y 
    // la extensión del arxhivo.
    ...
    input: ['resources/scss/app.scss', 'resources/js/app.js'],
    ...
    


    En segundo lugar, en la misma sección de plugins, ingresaremos una solución de Freek van Der Harten , que nos permite ver los cambios que realicemos tanto en los archivos css o js en tiempo real.

    En tercer lugar, vamos a utilizar otra solución del querido Freek , que nos permite resolver el bloqueo que algunos navegadores aplican cuando se invoca a los archivos css o js que se encuentran servidos por Vite.

    El archivo de configuración, quedaría de la siguiente forma;

    import fs from 'fs';
    import { defineConfig } from 'vite';
    import laravel from 'laravel-vite-plugin';
    import { homedir } from 'os';
    import { resolve } from 'path';
    
    let host = 'calendario.dev'
    
    export default defineConfig({
        plugins: [
            laravel({
                input: ['resources/scss/app.scss', 'resources/js/app.js'],
                refresh: true,
            }),
            // Esto hace que al hacer un cambio en el css o lo que sea, 
            // se refresque automágicamente en la vista
            // Freek Laravel
            {
                name: 'blade',
                handleHotUpdate({ file, server }) {
                    if (file.endsWith('.blade.php')) {
                        server.ws.send({
                            type: 'full-reload',
                            path: '*',
                        });
                    }
                },
            }
        ],
        server: detectServerConfig(host),
    });
    
    function detectServerConfig(host) {
        let keyPath = resolve(homedir(), `.config/valet/Certificates/${host}.key`)
        let certificatePath = resolve(homedir(), `.config/valet/Certificates/${host}.crt`)
    
        if (!fs.existsSync(keyPath)) {
            return {}
        }
    
        if (!fs.existsSync(certificatePath)) {
            return {}
        }
    
        return {
            hmr: { host },
            host,
            https: {
                key: fs.readFileSync(keyPath),
                cert: fs.readFileSync(certificatePath),
            },
        }
    }
    


    ¡Manos a la obra!, 라 비스타.



    Nos vamos a complicar con crear nuevas vistas, utilizaremos la misma vista de bienvenida que viene por defto de Laravel;

    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
    
            <title>Calendario</title>
    
            @vite(['resources/scss/app.scss', 'resources/js/app.js'])
    
            @livewireStyles
    
        </head>
        <body>
    
            <livewire:calendario />
    
            @livewireScripts
        </body>
    </html>
    


    Como puede verse, es una muy simple implementación, para mayor detalles sobre cómo integrar un modulo Livewire en una vista, pueden echarle un ojo a este artículo 공식 문서로.

    비스타 드 라이브와이어



    En el archivo resources/views/livewire/calendario.blade.php deben implementar lo siguiente;

    <div>
        {{-- The Master doesn't talk, he acts. --}}
        <div class="calendar">
            <div></div>
          <div class="cabecera">
            <i class="fas fa-angle-left nav" wire:click="decrementar('m')"></i>
            <div>{{ $meses[$countMes] }}</div>
            <i class="fas fa-angle-right nav" wire:click="incrementar('m')"></i>
    
            <i class="fas fa-angle-left nav" wire:click="decrementar('a')"></i>
            <div><span class="year">{{ $anio }}</span></div>
            <i class="fas fa-angle-right nav " wire:click="incrementar('a')"></i>
          </div>
    
          <div class="days">
            @foreach ($etiquetaDias as $dia)
            <span>{{ $dia }}</span>
            @endforeach
          </div>
    
          <div class="dates">
            @php
              $extraClass = "";
            @endphp
    
            @while ($inicioCalendario <= $finCalendario)
    
              @php
                $extraClass = $inicioCalendario->format('m') != $fecha->format('m') ? 'deshabilitado' : '';
                $extraClass .= $inicioCalendario->isToday() ? ' today ' : '';
              @endphp
    
              <button  class="{{ $extraClass }}" >
                <time>{{ $inicioCalendario->format('j') }}</time>
              </button>
    
              @php
                $inicioCalendario->addDay();
              @endphp 
            @endwhile
          </div>
        </div>
      </div>
    


    Esto es básicamente la forma en que se arma el calendario, nos valdremos de Carbon para armar un calendario de la forma mas sencilla posible, el artículo de donde obtengo esta porción de código es el siguiente .

    El Componente, o Controlador del calendario



    Con Livewire, no llevamos la logica en un controlador de la clase Controller como es lo común en Laravel, si no que se crea un nuevo componente en el directorio app/Http/Livewire/Calendario.php, en donde escribiremos lo siguiente;

    <?php
    
    namespace App\Http\Livewire;
    
    use Livewire\Component;
    use Illuminate\Support\Carbon;
    
    class Calendario extends Component
    {
        protected $currentDateTime;
    
        public $inicioCalendario;
        public $finCalendario;
        public $fecha;
        public $anio;
        public $countMes = 1;
        public $etiquetaDias = ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'];
        public $meses = [ 1 => 'Enero',
                          2 => 'Febrero',
                          3 => 'Marzo',
                          4 => 'Abril',
                          5 => 'Mayo',
                          6 => 'Junio',
                          7 => 'Julio',
                          8 => 'Agosto',
                          9 => 'Septiembre',
                          10 => 'Octubre',
                          11 => 'Noviembre',
                          12 => 'Diciembre', ];
    
        // inicializamos calendario
        public function mount()
        {
            $this->currentDateTime = now();
    
            $this->countMes = $this->currentDateTime->format('n');
            $this->inicioCalendario = $this->currentDateTime->copy()->firstOfMonth()->startOfWeek(Carbon::SUNDAY);
            $this->finCalendario = $this->currentDateTime->copy()->lastOfMonth()->endOfWeek(Carbon::SATURDAY);
            $this->fecha = $this->currentDateTime->copy();
            $this->anio = $this->currentDateTime->copy()->format('Y');
        }
    
        /**
         * Metodo para incrementar, tanto por mes, como por año
         */
        public function incrementar($objeto)
        {
            // Creamos una instacia de la fecha con el mes, y año que está en la vista
            $this->currentDateTime = Carbon::createFromFormat('n/Y', $this->countMes.'/'.$this->anio);
    
            // Si el parametro es M es porque se incrementa un mes,
            // por lo que nos valemos del metodo addMonth de Carbon
            if ($objeto == "m") {
                $this->inicioCalendario = $this->currentDateTime->copy()
                                                ->addMonth()
                                                ->firstOfMonth()
                                                ->startOfWeek(Carbon::SUNDAY);
                $this->finCalendario = $this->currentDateTime->copy()
                                            ->addMonth()
                                            ->lastOfMonth()
                                            ->endOfWeek(Carbon::SATURDAY);
    
                // establecemos los valores para mes y año que figuran en la vista
                $this->countMes = (int) $this->currentDateTime->copy()->addMonth()->format('n');
                $this->anio = (int) $this->currentDateTime->copy()->addMonth()->format('Y');
            } else {
                // Si el parametro es A es porque se incrementa un año,
                // por lo que nos valemos del metodo addYear de Carbon
                $this->inicioCalendario = $this->currentDateTime->copy()
                                                ->addYear()
                                                ->firstOfMonth()
                                                ->startOfWeek(Carbon::SUNDAY);
                $this->finCalendario = $this->currentDateTime->copy()
                                            ->addYear()
                                            ->lastOfMonth()
                                            ->endOfWeek(Carbon::SATURDAY);
                // establecemos los valores para mes y año que figuran en la vista
                $this->countMes = (int) $this->currentDateTime->copy()->addYear()->format('n');
                $this->anio = (int) $this->currentDateTime->copy()->addYear()->format('Y');
            }
        }
    
        /**
         * Metodo para decrementar, tanto por mes, como por año
         * La lógica es la misma que para el incremento,
         * pero utilizando los metodos subMonth y subYear de Carbon
         */
        public function decrementar($objeto)
        {
            $this->currentDateTime = Carbon::createFromFormat('n/Y', $this->countMes.'/'.$this->anio);
    
            if ($objeto == "m") {
                $this->inicioCalendario = $this->currentDateTime->copy()
                                                ->subMonth()
                                                ->firstOfMonth()
                                                ->startOfWeek(Carbon::SUNDAY);
                $this->finCalendario = $this->currentDateTime->copy()
                                            ->subMonth()
                                            ->lastOfMonth()
                                            ->endOfWeek(Carbon::SATURDAY);
    
                $this->countMes = (int) $this->currentDateTime->copy()->subMonth()->format('n');
                $this->anio = (int) $this->currentDateTime->copy()->subMonth()->format('Y');
            } else {
                $this->inicioCalendario = $this->currentDateTime->copy()
                                                ->subYear()
                                                ->firstOfMonth()
                                                ->startOfWeek(Carbon::SUNDAY);
                $this->finCalendario = $this->currentDateTime->copy()
                                            ->subYear()
                                            ->lastOfMonth()
                                        ->endOfWeek(Carbon::SATURDAY);
    
                $this->countMes = (int) $this->currentDateTime->copy()->subYear()->format('n');
                $this->anio = (int) $this->currentDateTime->copy()->subYear()->format('Y');
            }
        }
    
        /**
         * Renderizado de la vista
         */
        public function render()
        {
            return view('livewire.calendario');
        }
    }
    


    충분한 의견을 제시할 수 있는 코드가 없으면 문제가 해결되지 않습니다.

    포르마토



    Por último, en el archivo resources/scss/app.scss vamos a definir los estilos para el calendario;

    $fa-font-path: "@fortawesome/fontawesome-free/webfonts";
    @import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
    @import "@fortawesome/fontawesome-free/scss/solid.scss";
    @import "@fortawesome/fontawesome-free/scss/brands.scss";
    @import "@fortawesome/fontawesome-free/scss/regular.scss";
    body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
    }
    
    .calendar {
        display: inline-grid;
        justify-content: center;
        align-items: center;
        background: #fff;
        padding: 20px;
        .cabecera {
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 20px;
            margin-bottom: 20px;
            font-weight: 300;
            .year {
                font-weight: 600;
                margin-left: 10px;
            }
            .nav {
                display: flex;
                justify-content: center;
                align-items: center;
                text-decoration: none;
                color: #0a3d62;
                width: 40px;
                height: 40px;
                border-radius: 10px;
                transition-duration: 0.2s;
                position: relative;
                &:hover {
                    background: #eee;
                }
            }
        }
        .days {
            display: grid;
            justify-content: center;
            align-items: center;
            grid-template-columns: repeat(7, 1fr);
            color: #999;
            font-weight: 600;
            margin-bottom: 15px;
            span {
                width: 50px;
                justify-self: center;
                align-self: center;
                text-align: center;
            }
        }
        .dates {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            button {
                cursor: pointer;
                outline: 0;
                border: 0;
                background: transparent;
                font-family: "Montserrat", sans-serif;
                font-size: 16px;
                justify-self: center;
                align-self: center;
                width: 50px;
                height: 50px;
                border-radius: 10px;
                margin: 2px;
                transition-duration: 0.2s;
                &.today {
                    box-shadow: inset 0px 0px 0px 2px #0a3d62;
                }
                &.ocupado {
                    background: #0a3d62;
                    color: #fff;
                    font-weight: 600;
                    &:hover {
                        background: #a9a;
                    }
                }
                &.deshabilitado {
                    color: #aaa;
                    font-weight: 600;
                }
                &:hover {
                    background: #eee;
                }
            }
        }
    }
    


    엘 결과



    Con la utilizacion de Vite, a medida que escriben podrán ir viendo los resultados sin necesidad de recargar la pagina, de todas les dejo el calendario terminado;



    ¿Y 아호라?



    Ahora resta aplicarle mas complejidad, como una conexion a la base de datos para poder registrar eventos para una aplicacion de schedules, por ejemplo, les dejo el código fuente del proyecto para que descarguen y despejen cualquier duda.

    좋은 웹페이지 즐겨찾기