Laravel Lessons: Views & Layouts

Published April 24, 2020 • 11 mins read

In the previous lesson, we set up the frontend routes of our email sending app.

In this lesson will focus on building the frontend of our email sending application. We will be using Tailwindcss for the frontend and a little Alpine.js. We will be pulling some already made components from TailwindComponents.

Views are files that contains the html content of our application. Laravel views are stored inside the resources/views directory as blade files with .blade.php file extension.

Blade Templating Engine

Blade templating engine is a PHP template engine that ships with Laravel.

A PHP template engine is a way of outputting PHP in your HTML without using PHP syntax or PHP tags.

The blade templating engine has lots of cool features like template inheritance, sections, control structures(if, loop, foreach etc), components, stacks etc. Almost all the features of the blade templating engine can be accessed through blade directives. For example if you want to add if statement to a blade file we call the @if(true) @endif directives. D

Lets go through some of the basics of blade template engine that will help us set up our views and layout files.

Assets

Assets are CSS, JavaScripts and images. These files are stored inside the public directory. You can create your css and js directories here. Laravel provides a helper function, asset($path), which generates a URL for your assets.

All the files inside public directory and are publicly accessible.

LiteMailer Layout

Blade template offers what is called template inheritance that allows us to define a layout view file that other view files will extend from. This means that we don't need to copy and paste the page header and footer on all view files. We will just inherit them through the @extend directive. Lets setup our app layout.

Remember that all Laravel blade views resides in the resources/views directory.

Create a layout.blade.php file.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Titillium+Web:400,400i,600,600i,700&display=swap"
        rel="stylesheet">
    <title>@yield('title') | LiteMailer</title>
    <script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js" defer></script>
</head>
<body class="min-h-screen">
    @include('navbar')
    <main>
        @yield('content')
    </main>
    @include('footer')
</body>
</html>

Let me explain the blade directives we used here:

@yield & @section : The @yield blade directive is used to display both strings and html content inside our blade view. The @section directive is used to define the content of our @yield directive. The @section has a closing directive called @endsection. Lots of blade directives do :)

@include : This blade directive is used to include a blade view inside another blade view. Thats how we added our navbar and footer to our blade layout file.

Navbar

We have already included our navbar and footer blade views inside our layout file, now lets create it.

Create a navbar.blade.php and add the html code below

 <!-- navbar -->
<!-- AlpineJs is used to implements our hamburger menu for mobile devices. -->
<header x-data="{ openNav: false }"
    :class="{'bg-white': openNav === true }"
    class="py-4 px-6 absolute top-0 left-0 right-0 z-10">
    <div class="container mx-auto">
        <nav class="flex items-center justify-between flex-wrap">
            <div class="flex items-center flex-shrink-0 mr-6">
                <a href="{{url('/')}}" class="text-3xl font-bold">LiteMailer</a>
            </div>
            <div class="block lg:hidden">
                <button @click="openNav = !openNav" class="flex items-center px-3 py-2">
                    <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
                        <path x-show="!openNav" fill-rule="evenodd"
                            d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z"
                            clip-rule="evenodd" style="display: none;"></path>
                        <path x-show="openNav" fill-rule="evenodd"
                            d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
                            clip-rule="evenodd"></path>
                    </svg>
                </button>
            </div>
            <div :class="{'hidden': openNav === false }"
                class="w-full block flex-grow lg:flex lg:items-center lg:w-auto">
                <div class="text-sm lg:flex-grow">
                </div>
                <div>
                    <a href="{{url('/')}}" class="block mt-4 lg:inline-block lg:mt-0  font-bold uppercase mr-4">
                        Home
                    </a>
                    <a href="{{url('email/send')}}"
                        class="block mt-4 lg:inline-block lg:mt-0  font-bold uppercase mr-4">
                        Send Bulk EMail
                    </a>
                    <a href="{{url('email/add')}}" class="block mt-4 lg:inline-block lg:mt-0  font-bold uppercase mr-4">
                        Add New EMail
                    </a>
                </div>
            </div>
        </nav>
    </div>
</header>

We used the url helper function to add the navigation links. This function appends our base url to the given path. Example: url('email/add') will return http://litemailer.test/email/add.

Footer

Create a footer.blade.php and add the html code below

 <!-- footer -->
<footer class="pt-12">
    <div class="bg-blue-100">
        <div class="container mx-auto px-6 py-6  text-center border-t border-gray-300">
            <p>LiteMailer {{ date('Y') }}
                | Fork on <a href="https://github.com/stephenjude/litemailer" class="font-bold underline">Github</a>
                | Made with <a class="font-bold underline" href="https://tailwindcss.com">TailwindCSS</a>,
                <a class="font-bold underline" href="https://github.com/alpinejs/alpine">AlpineJs</a> &
                <a class="font-bold underline" href="https://tailwindcomponents.com">TailwindComponents</a>
            </p>
        </div>
    </div>
</footer>

Welcome Page

Now that our blade layout view is ready, our welcome page is going to extend from it. Extending another blade file is done through the @extend('bladefile') directive. You have to specify the blade file you want to extend from.

We are going to use the asset() helper function to load our asset files. You can download the asset files here. Create an images directory inside the public directory and move the asset files there.

Lets update welcome.blade.php file with the html code below

@extends('layout')
@section('title', 'Welcome')
@section('content')
<div class="relative overflow-hidden px-6 pb-6">
    <img src="{{ asset('images/wave.svg') }}" class="absolute top-0 left-2/5">
    <div class="container mx-auto relative">
        <div class="flex flex-col md:flex-row items-center pt-32 pb-16 md:pb-0">
            <div class="md:w-1/2 lg:w-1/3 mb-4 sm:mb-16 md:mb-0">
                <h1 class="text-4xl md:text-5xl font-bold leading-tight mb-6 md:mb-10">
                    Bulk email software for email marketing
                </h1>
                <p class="text-xl ">
                    You can check how we built it by following this <a class="text-teal-500 text-"
                        href="http://stephenjude.me/series/laravel-lessons">blog series</a>.
                </p>
            </div>
            <div class="mt-16 sm:mt-0 flex-1 flex justify-end">
                <img src="{{ asset('images/hero.svg') }}">
            </div>
        </div>
    </div>
</div>
@endsection

Like I explained earlier, the @section directive is used to add content to the @yield directive. Thats what we did.

@section('title', 'Welcome')

If you are wondering what this means, its just a way of passing string content to the @yield directive.

Add New Email Page

Create add-email.blade.php and update it with the html code below

@extends('layout')
@section('title', 'Send Builk Email')
@section('content')
<div class="relative overflow-hidden px-6 pb-6">
    <img src="{{ asset('images/wave.svg') }}" class="absolute top-0 left-2/5">
    <div class="container mx-auto relative">
        <div class="flex flex-col md:flex-row items-center pt-32 pb-16 md:pb-0">
            <div class="w-full shadow-lg md:w-1/2 lg:w-1/2 mb-4 sm:mb-16 md:mb-0 bg-white rounded-lg">
                <h3 class="pt-4 text-2xl text-center">Add New Email</h3>
                <form class="px-8 pt-6 pb-8 mb-4">
                    <div class="mb-4">
                        <label class="block mb-2 text-sm font-bold text-gray-700">
                            Name
                        </label>
                        <input
                            class="w-full px-3 py-3 text-sm leading-tight text-gray-700 border rounded shadow appearance-none focus:outline-none focus:shadow-outline"
                            type="text" placeholder="Enter your name" />
                    </div>
                    <div class="mb-8">
                        <label class="block mb-2 text-sm font-bold text-gray-700">
                            Email
                        </label>
                        <input
                            class="w-full px-3 py-3 text-sm leading-tight text-gray-700 border rounded shadow appearance-none focus:outline-none focus:shadow-outline"
                            type="email" placeholder="Enter your email" />
                    </div>
                    <div class="mb-6 text-center">
                        <button
                            class="w-full px-4 py-2 font-bold text-white bg-teal-400 rounded-full hover:bg-teal-500 focus:outline-none focus:shadow-outline"
                            type="button">
                            Submit
                        </button>
                    </div>
                </form>
            </div>
            <div class="mt-16 sm:mt-0 flex-1 flex justify-end">
                <img src="{{ asset('images/hero.svg') }}">
            </div>
        </div>
    </div>
</div>
@endsection

Send Email Page

Create send-email.blade.php and update it with the html code below

@extends('layout')
@section('title', 'Send Builk Email')
@section('content')
<div class="relative overflow-hidden px-6 pb-6">
    <img src="{{ asset('images/wave.svg') }}" class="absolute top-0 left-2/5">
    <div class="container mx-auto relative">
        <div class="flex flex-col md:flex-row items-center pt-32 pb-16 md:pb-0">
            <div class="w-full shadow-lg  md:w-1/2 lg:w-1/2 mb-4 sm:mb-16 md:mb-0 bg-white rounded-lg">
                <h3 class="pt-4 text-2xl text-center">Send Bulk Email</h3>
                <form class="px-8 pt-6 pb-8 mb-4">
                    <div class="mb-4">
                        <label class="block mb-2 text-sm font-bold text-gray-700">
                            Subject
                        </label>
                        <input
                            class="w-full px-3 py-3 text-sm leading-tight text-gray-700 border rounded shadow appearance-none focus:outline-none focus:shadow-outline"
                            type="text" placeholder="Enter email subject" />
                    </div>
                    <div class="mb-4">
                        <label class="block mb-2 text-sm font-bold text-gray-700">
                            Message
                        </label>
                        <textarea
                            class="w-full px-3 py-2 text-sm leading-tight text-gray-700 border rounded shadow appearance-none focus:outline-none focus:shadow-outline"
                            rows="12" placeholder="Message goes here..."></textarea>
                    </div>
                    <div class="mb-6 text-center">
                        <button
                            class="w-full px-4 py-2 font-bold text-white bg-teal-400 rounded-full hover:bg-teal-500 focus:outline-none focus:shadow-outline"
                            type="button">
                            Send
                        </button>
                    </div>
                </form>
            </div>
            <div class="mt-16 sm:mt-0 flex-1 flex justify-end">
                <img src="{{ asset('images/hero.svg') }}">
            </div>
        </div>
    </div>
</div>
@endsection

There is a lot more to Laravel blade templating engine, we will cover them as we progress in the coming lessons.

Now that our frontend is ready, we will be moving to the next lesson: Laravel Controller, Requests and Validations.

Questions

Drop your question on the comment box, send me a DM on twitter or send an e-mail.

Subscribe here to receive email updates of this series directly to your inbox.

Hey, have you tried Litehost lately?

Litehost is my side project which is a shared hosting platform with PHP & Laravel developers in mind. It has Composer, Git & PHP CLI pre-installed on its servers. SSH access is also granted on request. Litehost is pretty affordable. Try it today.