Componente para Sub-Menu * Laravel/Breeze * Tailwind

Cuando instalas Laravel/Breeze la plantilla del menú de navegación tiene el menú principal a la izquierda y un dropdown a la derecha, sin embargo no hay ningún componente dentro del menú principal que se pueda usar para un sub-menú.

El paquete Laravel/Breeze agrega plantillas específicas para el menú y además usa Tailwind, algo que es muy nuevo para mí, y luego de tener unos problemas al momento de instalar Laravel/Breeze y conflicto con las dependencias, finalmente pude trabajar en otras cosas, hasta que llegué a la parte del menú.

El componente del menú tiene un dropdown que muestra acciones al usuario como cerrar la sesión.

Al lado derecho está el dropdown disponible

Para el proyecto que estoy trabajando necesito tener un menú principal con varias opciones:

Menú que necesito

Componentes

Siguiendo la misma lógica de los componentes originales procedí a crear dos componentes para versión móvil y de escritorio.

nav-link-parent.blade.php

@props(['active'])

@php
$classes = ($active ?? false)
            ? 'parent-nav inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-semibold leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out cursor-pointer relative'
            : 'parent-nav inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-semibold leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out cursor-pointer relative';
@endphp

<div x-data="{ open: false }" @click.away="open = false" @close.stop="open = false" @click="open = ! open" {{ $attributes->merge(['class' => $classes]) }} >
    <div>
        {{ $name }}

        <div class="ml-1 inline-block relative top-1">
            <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
            </svg>
        </div>
    </div>

    <div class="children border border-gray-300" 
    x-show="open"
    x-transition:enter="transition ease-out duration-200"
    x-transition:enter-start="transform opacity-0 scale-95"
    x-transition:enter-end="transform opacity-100 scale-100"
    x-transition:leave="transition ease-in duration-75"
    x-transition:leave-start="transform opacity-100 scale-100"
    x-transition:leave-end="transform opacity-0 scale-95">
        {{ $children }}
    </div>
</div>

responsive-nav-link-parent.blade.php

@props(['active'])

@php
$classes = ($active ?? false)
            ? 'parent-nav inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-semibold leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out'
            : 'parent-nav inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-semibold leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out';
@endphp

@props(['active'])

@php
$classes = ($active ?? false)
            ? 'parent-nav block pl-3 pr-4 py-2 border-l-4 border-indigo-400 text-base font-semibold text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
            : 'parent-nav block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-semibold text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out';
@endphp

<div x-data="{ open: false }" @click.away="open = false" @close.stop="open = false" @click="open = ! open" {{ $attributes->merge(['class' => $classes]) }} >
    <div>
        {{ $name }}

        <div class="ml-1 inline-block relative top-1">
            <svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
                <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
            </svg>
        </div>
    </div>

    <div class="children border border-gray-300 mt-3" 
    x-show="open"
    x-transition:enter="transition ease-out duration-200"
    x-transition:enter-start="transform opacity-0 scale-95"
    x-transition:enter-end="transform opacity-100 scale-100"
    x-transition:leave="transition ease-in duration-75"
    x-transition:leave-start="transform opacity-100 scale-100"
    x-transition:leave-end="transform opacity-0 scale-95">
        {{ $children }}
    </div>
</div>

Estilos

Algo de CSS para ajustar la posición y detalles del elemento.

.children {
    background: #fff;
}

.children a,
.children .separator {
    display: block;
    margin: 5px 0px;
    padding: 5px 10px;
}

.children .separator {
    border-top-width: 2px;
}

.children a:hover {
    color: #818cf8;
}

@media (min-width: 768px) {
    .children {
        position: absolute;
        width: 155px;
        top: 70px;
    }
}

Actualizar el componente

Por último actualicé el archivo de la plantilla correspondiente al componte del menú de navegación.

navigation.blade.php

...
<x-nav-link-parent :href="'#'" :active="request()->routeIs('padron.*')">
    <x-slot name="name">Option A</x-slot>
    <x-slot name="children">
        <a href="#">Item A</a>
        <span class="separator"></span>
        <a href="#">Item B</a>
        <a href="#">Item C</a>
        <span class="separator"></span>
        <a href="#">Item D</a>
    </x-slot>
</x-nav-link-parent>
...
<x-responsive-nav-link-parent :href="'#'" :active="request()->routeIs('padron.*')">
    <x-slot name="name">Padrón</x-slot>
    <x-slot name="children">
        <a href="#">Buscador</a>
        <span class="separator"></span>
        <a href="#">Centros de votacion</a>
        <a href="#">Juntas</a>
        <span class="separator"></span>
        <a href="#">Cartografia</a>
    </x-slot>
</x-responsive-nav-link-parent>

Resultado Final

Image by Free-Photos from Pixabay

Dependencias Desactualizadas

En la publicación anterior sobre Laravel/Breeze te comentaba como había tenido un pequeño problema al no tener la versión más reciente de Php. Laravel/Breeze se instaló bien, pero cuando quiero usar npm run dev da otro error, no puede compilar lo que está en app.css.

Continue reading “Dependencias Desactualizadas”