Skip to Content
TemplatesLayouts

Layouts

Layouts define the general structure of an HTML page: where the header and footer are, how styles and scripts are included.

Structure of app.blade.php

The main layout is located in views/layouts/app.blade.php. When inheriting from standard, it already exists, but it can be overridden.

Simplified Structure

<!DOCTYPE html> <html lang="..." data-theme="dark|light"> <head> <!-- Meta tags, title, description --> @stack('head') @stack('styles') <!-- Include SCSS theme --> @at(tt('assets/sass/app.scss')) <!-- HTMX and scripts --> </head> <body> <!-- Header --> @include('flute::layouts.header') <!-- Main Content --> <main id="main"> @stack('content') </main> <!-- Footer --> @include('flute::layouts.footer') <!-- Modals --> <div id="modals"> @stack('modals') </div> <!-- Scripts --> @at(tt('assets/scripts/app.js')) @stack('scripts') </body> </html>

Overriding Header

Create views/layouts/header.blade.php:

<header class="my-header"> <div class="container"> <div class="header-content"> {{-- Logo --}} <a href="{{ url('/') }}" class="logo"> <img src="{{ asset(config('app.logo')) }}" alt="{{ config('app.name') }}"> </a> {{-- Navigation --}} <nav class="nav"> @foreach (navbar()->all() as $item) @if (count($item['children']) === 0) {{-- Regular link --}} <a href="{{ url($item['url']) }}" class="nav-link {{ active($item['url']) }}" @if ($item['new_tab']) target="_blank" @endif> @if ($item['icon']) <x-icon :path="$item['icon']" /> @endif {{ __($item['title']) }} </a> @else {{-- Dropdown --}} <div class="nav-dropdown"> <button class="nav-link" data-dropdown-open="nav-{{ $loop->index }}" data-dropdown-hover="true"> @if ($item['icon']) <x-icon :path="$item['icon']" /> @endif {{ __($item['title']) }} <x-icon path="ph.regular.caret-down" /> </button> <div data-dropdown="nav-{{ $loop->index }}" class="dropdown"> @foreach ($item['children'] as $child) <a href="{{ url($child['url']) }}" class="dropdown__item"> @if ($child['icon']) <x-icon :path="$child['icon']" /> @endif {{ __($child['title']) }} </a> @endforeach </div> </div> @endif @endforeach </nav> {{-- Actions --}} <div class="header-actions"> {{-- Theme Switcher --}} <x-header.theme-switcher /> @auth {{-- Notifications --}} <x-header.notifications /> {{-- Profile --}} <x-header.profile /> @else {{-- Login Button --}} <x-button href="{{ url('login') }}" size="small"> @t('def.login') </x-button> <x-button href="{{ url('register') }}" size="small" type="accent"> @t('def.register') </x-button> @endauth </div> {{-- Mobile Menu --}} <button class="mobile-menu-btn" data-trigger-right-sidebar> <x-icon path="ph.bold.list" /> </button> </div> </div> </header>

Styles for Header

// assets/sass/layouts/_header.scss .my-header { position: sticky; top: 0; z-index: 100; background: var(--blurred-background); backdrop-filter: blur(20px); border-bottom: 1px solid var(--transp-1); } .header-content { display: flex; align-items: center; justify-content: space-between; height: 64px; gap: var(--space-lg); } .logo img { height: 32px; width: auto; } .nav { display: flex; align-items: center; gap: var(--space-xs); @include media(mobile) { display: none; } } .nav-link { display: flex; align-items: center; gap: var(--space-xs); padding: var(--space-xs) var(--space-sm); border-radius: var(--border05); font-size: var(--p); font-weight: 500; color: var(--text-muted); @include transition(all); &:hover, &.active { color: var(--text); background: var(--transp-1); } } .header-actions { display: flex; align-items: center; gap: var(--space-sm); } .mobile-menu-btn { display: none; @include media(mobile) { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; } }

Create views/layouts/footer.blade.php:

<footer class="my-footer"> <div class="container"> <div class="footer-content"> {{-- Logo and description --}} <div class="footer-brand"> <img src="{{ asset(config('app.logo')) }}" alt="{{ config('app.name') }}"> <p>{{ config('app.description') }}</p> {{-- Socials --}} <x-footer.socials /> </div> {{-- Links from admin panel --}} <div class="footer-links"> <x-footer.links /> </div> </div> <div class="footer-bottom"> <x-footer.copyright /> </div> </div> </footer>

Stacks (@stack / @push)

Stacks allow you to add content to specific places in the layout.

Available Stacks

StackWhere it outputsPurpose
headIn <head>Meta tags
stylesIn <head>CSS files
scriptsBefore </body>JavaScript
modalsIn #modalsModal windows
contentIn <main>Main content
before-contentBefore <main>Banners
content-afterAfter <main>Additional blocks

Usage Examples

{{-- Add styles --}} @push('styles') <link rel="stylesheet" href="/my-styles.css"> @at('Modules/Shop/Resources/assets/scss/shop.scss') @endpush {{-- Add scripts --}} @push('scripts') <script src="/my-script.js"></script> @at('Modules/Shop/Resources/assets/js/shop.js') <script> document.addEventListener('DOMContentLoaded', () => { console.log('Page loaded'); }); </script> @endpush {{-- Add modal --}} @push('modals') <x-modal id="my-modal" title="Title"> ... </x-modal> @endpush {{-- Add meta tags --}} @push('head') <meta property="og:type" content="article"> <meta name="robots" content="noindex"> @endpush

Useful Helpers in Templates

User

{{-- Check authorization --}} @auth <p>Hello, {{ user()->name }}!</p> @else <p>You are not logged in</p> @endauth {{-- Short syntax --}} @guest <a href="{{ url('login') }}">Login</a> @endguest

Permissions

@can('admin') <a href="{{ url('admin') }}">Admin Panel</a> @endcan @cannot('admin') <p>No access</p> @endcannot

URL and Assets

{{-- URL --}} {{ url('/profile') }} {{ url()->current() }} {{-- Assets --}} {{ asset('images/logo.png') }} @asset('assets/js/app.js') {{-- Path to theme --}} @at(tt('assets/sass/app.scss'))

Translations

@t('def.login') @t('messages.welcome', ['name' => $user->name]) {{ __('messages.hello') }}

Configuration

{{ config('app.name') }} {{ config('app.description') }} {{ config('app.logo') }}
{{-- All menu items --}} @foreach (navbar()->all() as $item) {{ $item['title'] }} {{ $item['url'] }} {{ $item['icon'] }} {{ $item['children'] }} @endforeach {{-- Footer columns --}} @foreach (footer()->all() as $column) ... @endforeach

Blade Directives

Conditions

@if ($condition) ... @elseif ($other) ... @else ... @endif @unless ($condition) {{-- If condition is false --}} @endunless

Loops

@foreach ($items as $item) {{ $loop->index }} {{-- 0, 1, 2... --}} {{ $loop->iteration }} {{-- 1, 2, 3... --}} {{ $loop->first }} {{-- true if first --}} {{ $loop->last }} {{-- true if last --}} @endforeach @forelse ($items as $item) {{ $item }} @empty <p>No elements</p> @endforelse

Including Templates

@include('partials.sidebar') @include('partials.card', ['title' => 'Hello']) @includeWhen($condition, 'partials.sidebar') @includeUnless($condition, 'partials.sidebar')

PHP Code

@php $total = $items->sum('price'); @endphp {{ $total }}

HTMX Integration

The layout is configured to work with HTMX — dynamic updates without page reloads.

How it Works

  1. <body> has HTMX extension attributes.
  2. <main id="main"> is the container for swap content.
  3. Navigation uses hx-boost for SPA-like transitions.

Checking HTMX Request

@php $isPartialRequest = request()->htmx()->isHtmxRequest(); @endphp @if (!$isPartialRequest) {{-- Full HTML (first load) --}} @else {{-- Content only (HTMX swap) --}} @endif

With HTMX requests, header/footer are not re-rendered — only <main> is updated.