Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Voir cette série
Shop V2 : la page d'accueil
Vendredi 31 juillet 2026 21:37

Nous allons à présent nous concentrer sur la mise en place du frontend en commençant par la page d'accueil. Nous allons utiliser MaryUI et son compagnon Livewire. Il faudra afficher les produits sur cette page, mais aussi les barres de navigations nécessaires en prévoyant la possibilité de naviguer sur un écran étroit.

Le code complet à la fin de cet article peut être téléchargé ici.

Installation de MaryUI

Nous allons commencer par installer MaryUI :

composer require robsontenorio/mary
php artisan mary:install

Ça va également installer Livewire.

Concernant l'outil à utiliser, choisissez npm. Il va s'installer de nombreuses dépendances, en particulier DaisyUI et Tailwind. Il ne reste plus qu'à générer avec Vite! :

npm run dev

Votre page d'accueil devrait maintenant avoir cet aspect :
Vous avez à présent quelque chose de fonctionnel qui vous permet de comprendre comme fonction MaryUI, il y a un tuto complet ici. Libre à vous d'explorer tout ça, mais on va l'ignorer pour la suite de notre projet.

Avec Livewire 4, on utilise des composants et avec l'installation initiale de maryUI on a eu la création automatique d'un composant :

Si vous allez voir le code, vous trouverez deux parties :

  • une classe PHP pour la gestion
  • une partie HTML pour la vue

C'est le principe de base de Livewire 4 qui concentre dans le même fichier ce qui était habituellement séparé avec les précédentes versions de Livewire, à moins d'utiliser Volt;

En ce qui concerne le layout, il se trouve par défaut ici :

On dispose par défaut d'une page avec une barre de navigation rétractable sur la gauche. On va devoir modifier tout ça pour notre boutique.

Au niveau de la route qui a été créée pour afficher le composant, ça se passe évidemment dans route/web.php :

Route::livewire('/', 'pages::users.index');

Remarquez la syntaxe pour désigner l'emplacement du composant.

On va faire un peu de ménage en supprimant le dossier users et son contenu, ainsi que la vue welcome :

Évidemment à présent plus rien ne fonctionne, mais ne vous inquiétez pas...

Les langues

On veut une boutique multilingue, vous devez donc installer un package de langue :

composer require --dev laravel-lang/common

Dans le fichier .env, on précise qu'on veut le site en français (j'en profite pour ajouter d'autres précisions, adaptez selon votre cas) :

APP_NAME="Shop V2"

APP_URL=http://shop2.test

APP_LOCALE=fr

On génère les fichiers :

php artisan lang:update

Le composant pour la page d'accueil

La page d'accueil va être gérée par un composant page de Livewire, commençons par le créer :

php artisan make:livewire pages::index

On change aussi la route pour pointer ce composant :

Route::livewire('/', 'pages::index');

Vous obtenez quelque chose comme ça :

Le composant prend par défaut le layout layouts/app.blade.php qui a été créé par MaryUI. On va devoir le modifier pour qu'il corresponde à nos besoins.

La barre de navigation

On crée un composant Livewire pour la barre de navigation :

php artisan make:livewire navigation.navbar

On ajoute ce code :

<?php

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\{Auth, Session};
use Livewire\Component;
use Livewire\Attributes\On;
use Mary\Traits\Toast;

new class extends Component {
    use Toast;

    public function logout(): void
    {
        Auth::guard('web')->logout();
        Session::invalidate();
        Session::regenerateToken();
        $this->redirect('/');
    }
};
?>

<x-nav sticky full-width class="bg-blue-500 text-white shadow-lg">

    <x-slot:brand>
        {{-- Bouton du Drawer Mobile --}}
        <label for="main-drawer" class="mr-3 lg:hidden cursor-pointer hover:opacity-80 transition-opacity">
            <x-icon name="o-bars-3" class="w-6 h-6 text-white" />
        </label>

        <a href="/" wire:navigate class="hover:opacity-90 transition-opacity">
            <x-app-brand />
        </a>
    </x-slot:brand>

    <x-slot:actions>
        <div class="flex items-center gap-2">

            {{-- Menu Utilisateur --}}
            <div class="hidden lg:block">
                @if ($user = auth()->user())
                    <x-dropdown class="dropdown-end">
                        <x-slot:trigger>
                            <x-button
                                class="btn-ghost btn-sm text-white hover:bg-white/10"
                                icon="o-user-circle"
                            >
                                {{ $user->firstname ?: $user->name }}
                            </x-button>
                        </x-slot:trigger>

                        <x-menu class="p-2 bg-base-100 text-base-content rounded-box shadow-2xl min-w-56 space-y-1">
                            <x-menu-item
                                title="{{ __('Mon profil') }}"
                                link="/"
                                icon="o-user"
                            />
                            <x-menu-item
                                title="{{ __('Mes adresses') }}"
                                link="/"
                                icon="o-map-pin"
                            />
                            <x-menu-item
                                title="{{ __('Mes commandes') }}"
                                link="/"
                                icon="o-document-text"
                            />
                            <x-menu-item
                                title="{{ __('Confidentialité') }}"
                                link="/"
                                icon="o-shield-check"
                            />

                            <x-menu-separator />

                            <x-menu-item
                                title="{{ __('Déconnexion') }}"
                                wire:click="logout"
                                icon="o-arrow-right-on-rectangle"
                                class="text-error hover:bg-error/10 font-medium"
                            />
                        </x-menu>
                    </x-dropdown>
                @else
                    <x-button
                        label="{{ __('Connexion') }}"
                        link="/login"
                        class="btn-ghost btn-sm text-white hover:bg-white/10"
                        icon="o-arrow-right-on-rectangle"
                    />
                @endif
            </div>

        </div>
    </x-slot:actions>
</x-nav>

Dans le layout, vous retirez ce code qui concerne la navigation :

{{-- NAVBAR mobile only --}}
<x-nav sticky class="lg:hidden">
    <x-slot:brand>
        <x-app-brand />
    </x-slot:brand>
    <x-slot:actions>
        <label for="main-drawer" class="lg:hidden me-3">
            <x-icon name="o-bars-3" class="cursor-pointer" />
        </label>
    </x-slot:actions>
</x-nav>

Et vous insérez notre nouveau composant à la place :

{{-- NAVBAR --}}
<livewire:navigation.navbar />

Lors de son installation, MaryUI a créé aussi ce composant :

Il est destiné à afficher le logo de la boutique dans la partie gauche de la barre de navigation. On va adapter cette partie du code :

public function render(): View|Closure|string
{
    return <<<'HTML'
            <a href="/" wire:navigate>
                <!-- Hidden when collapsed -->
                <div {{ $attributes->class(["hidden-when-collapsed"]) }}>
                    <div class="">
                        <img src="{{ asset('storage/photos/logo.png') }}" alt="" class="h-auto w-26 sm:w-32 md:w-40 lg:w-48 xl:w-56">
                    </div>
                </div>

                <!-- Display when collapsed -->
                <div class="display-when-collapsed hidden mx-5 mt-4 lg:mb-6 h7">
                    <x-icon name="s-square-3-stack-3d" class="w-6 -mb-1 text-purple-500" />
                </div>
            </a>
        HTML;
}

L'image logo.png est dans le ZIP que j'ai mis à disposition dans le précédent article. À présent, on a notre barre de navigation avec le logo à gauche et le menu à droite :

La barre latérale

Sur petits écrans, on doit gérer la barre de navigation latérale. On crée aussi un composant pour celle-ci :

php artisan make:livewire navigation.sidebar

On va évidemment trouver un code très proche de la barre qu'on a vue ci-dessus :

<?php

use Illuminate\Support\Facades\{Auth, Session};
use Livewire\Component;

new class() extends Component {

    public function logout(): void
    {
        Auth::guard('web')->logout();
        Session::invalidate();
        Session::regenerateToken();
        $this->redirect('/');
    }
};
?>

<div>
    <x-menu activate-by-route>
        @if($user = auth()->user())
            <x-menu-separator />
            <x-list-item :item="$user" value="name" sub-value="email" no-separator no-hover class="-mx-2 -my-2! rounded">
                <x-slot:actions>
                    <x-button icon="o-power" wire:click="logout" class="btn-circle btn-ghost btn-xs" tooltip-left="{{ __('Logout') }}" no-wire-navigate />
                </x-slot:actions>
            </x-list-item>
            <x-menu-separator />
            <x-menu-item title="{{ __('Mon profil') }}" icon="o-user" link="/" />
            <x-menu-item title="{{ __('Mes adresses') }}" icon="o-map-pin" link="/" />
            <x-menu-item title="{{ __('Mes commandes') }}" icon="o-shopping-cart" link="/" />
            <x-menu-item title="{{ __('RGPD') }}" icon="o-lock-closed" link="/" />
            <x-menu-separator />
        @else
            <x-menu-item title="{{ __('Connexion') }}" link="/login" />
        @endif
    </x-menu>
</div>

Dans le layout, remplacez tout le x-main par celui-ci :

{{-- MAIN CONTENT --}}
<main id="main-content" class="flex-1">
    <x-main full-width>

        {{-- SIDEBAR --}}
        <x-slot:sidebar drawer="main-drawer" collapsible class="bg-base-100 lg:bg-inherit lg:hidden">
            <livewire:navigation.sidebar />
        </x-slot:sidebar>

        {{-- SLOT --}}
        <x-slot:content>
            <div>
                {{ $slot }}
            </div>
        </x-slot:content>

    </x-main>
</main>

La barre latérale devrait à présent fonctionner.

La page d'accueil

Pour le moment, notre composant index pour la page d'accueil est vide. On veut y présenter les produits de la boutique. Mais dans un premier temps, comme on va avoir besoin des données de base de la boutique dans pratiquement toutes les vues, on va partager ces données dans AppServiceProvider :

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use App\Models\Shop;

class AppServiceProvider extends ServiceProvider
{

    ...

    public function boot(): void
    {
        if(app()->runningInConsole()) {
            return;
        }
        
        View::share('shop', Shop::firstOrFail());
    }
}

Au passage, on prend une précaution pour éviter une erreur si on régénère la base de données.

Voilà le code du composant index :

<?php

use Livewire\Component;
use App\Models\Product;

new class extends Component
{
    public function with(): array
    {
        return [
            'products' => Product::whereActive(true)->get(),
        ];
    }
};
?>

<div class="min-h-screen py-8 bg-base-200/50">

    {{-- Alert de bienvenue --}}
    @if (session('registered'))
        <div class="max-w-7xl mx-auto px-4 mb-8">
            <x-alert
                title="{!! session('registered') !!}"
                icon="o-rocket-launch"
                class="alert-info shadow-lg"
                dismissible
            />
        </div>
    @endif

    {{-- Présentation du shop (provenant de View::share) --}}
    @if(isset($shop) && $shop->home)
        <section class="max-w-4xl mx-auto px-4 mb-12">
            <x-card class="shadow-xl bg-base-100">
                <div class="max-w-none text-base-content">
                    {!! $shop->home !!}
                </div>
            </x-card>
        </section>
    @endif

    {{-- Produits --}}
    <section id="products" class="max-w-6xl mx-auto px-4 mb-16">
        <h2 class="text-3xl font-extrabold text-center mb-10 tracking-tight">
            @lang('Nos produits')
        </h2>

        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
            @forelse ($products as $product)
                <x-card class="shadow-xl bg-base-100 hover:shadow-2xl transition-all duration-300 hover:-translate-y-1 group p-0 overflow-hidden">

                    {{-- Image & Badges --}}
                    <x-slot:figure class="relative aspect-square bg-base-200/50 overflow-hidden">
                        @if($product->image)
                            <a href="/" class="w-full h-full block">
                                <img
                                    src="{{ asset('storage/photos/' . $product->image) }}"
                                    alt="{{ $product->name }}"
                                    class="object-cover w-full h-full transition-transform duration-500 group-hover:scale-110"
                                    loading="lazy"
                                />
                            </a>
                        @else
                            <div class="flex items-center justify-center w-full h-full text-base-content/20">
                                <x-icon name="o-photo" class="w-20 h-20" />
                            </div>
                        @endif

                        {{-- Badges de stock --}}
                        @if(!$product->quantity)
                            <div class="absolute top-3 right-3">
                                <x-badge value="{{ __('Rupture de stock') }}" class="badge-error text-white font-bold border-none" />
                            </div>
                        @elseif($product->quantity < 5)
                            <div class="absolute top-3 right-3">
                                <x-badge value="{{ __('Derniers articles') }}" class="badge-warning text-white font-bold border-none" />
                            </div>
                        @endif
                    </x-slot:figure>

                    {{-- Informations produit --}}
                    <div class="flex flex-col h-full p-6">
                        <h3 class="text-xl font-bold text-base-content truncate" title="{{ $product->name }}">
                            {{ $product->name }}
                        </h3>

                        @if($product->description)
                            <p class="mt-2 text-sm text-base-content/70 line-clamp-2">
                                {{ Str::limit($product->description, 150) }}
                            </p>
                        @endif

                        <div class="flex items-center justify-between mt-auto pt-6">
                            <div class="flex flex-col">
                                <span class="text-2xl font-black text-primary">
                                    {{ number_format($product->price, 2, ',', ' ') }} €
                                </span>
                                <span class="text-xs font-semibold text-base-content/50 uppercase">TTC</span>
                            </div>

                            @if($product->quantity)
                                <x-button
                                    link="/"
                                    label="{{ __('Voir') }}"
                                    icon="o-eye"
                                    class="btn-primary btn-sm"
                                />
                            @else
                                <x-button
                                    label="{{ __('Indisponible') }}"
                                    class="btn-disabled btn-sm"
                                    disabled
                                />
                            @endif
                        </div>
                    </div>
                </x-card>
            @empty
                <div class="col-span-full py-20 text-center">
                    <x-icon name="o-archive-box-x-mark" class="w-24 h-24 mx-auto text-base-content/20 mb-4" />
                    <p class="text-xl font-semibold text-base-content/60">@lang('Aucun produit disponible pour le moment.')</p>
                </div>
            @endforelse
        </div>
    </section>

    {{-- Informations supplémentaires --}}
    @if(isset($shop))
        <section class="max-w-4xl mx-auto px-4 pb-8">
            <x-card class="shadow-xl bg-base-100 p-0 overflow-hidden">
                <x-accordion class="divide-y divide-base-200">

                    <x-collapse name="info1" class="px-2">
                        <x-slot:heading class="text-lg font-bold">
                            <div class="flex items-center gap-3">
                                <x-icon name="o-information-circle" class="w-6 h-6 text-primary" />
                                @lang('Informations générales')
                            </div>
                        </x-slot:heading>
                        <x-slot:content class="max-w-none text-base-content/80 mt-2">
                            {!! $shop->home_infos !!}
                        </x-slot:content>
                    </x-collapse>

                    <x-collapse name="info2" class="px-2">
                        <x-slot:heading class="text-lg font-bold">
                            <div class="flex items-center gap-3">
                                <x-icon name="o-truck" class="w-6 h-6 text-primary" />
                                @lang('Frais de livraison')
                            </div>
                        </x-slot:heading>
                        <x-slot:content class="max-w-none text-base-content/80 mt-2">
                            {!! $shop->home_shipping !!}
                        </x-slot:content>
                    </x-collapse>

                </x-accordion>
            </x-card>
        </section>
    @endif
</div>

Je n'ai pas prévu de pagination en partant du principe qu'on a une petite boutique avec peu de produits. Mais ça serait facile à ajouter.

On ajoute quelques traductions

"General informations": "Informations générales",
"Shipping charges": "Frais de port",

On obtient l'affichage :

Je ne montre pas l'aspect responsive, sur écran moyen, on a deux colonnes et une seule sur petit écran.

Le thème

On peut changer le thème de couleurs pour apporter une touche plus personnalisée. Par exemple, dans css/app.css ajoutez ce code :

/** daisyUI */
@plugin "daisyui" {
    themes: light --default, dark --prefersdark, corporate;
}

Et dans le layout app :

<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" data-theme="corporate" > 

Vous pouvez tester d'autres thèmes selon vos goûts. 

Vous pouvez vous amuser avec tout ça...

La navigation du bas de page

Pour être complet, on va ajouter le bas de page avec sa navigation. On crée le composant :

php artisan make:livewire navigation.footer

Avec ce code :

<?php

use Livewire\Component;

new class() extends Component {
    public $currentYear;

    public function mount()
    {
        $this->currentYear = date('Y');
    }
};
?>

<footer class="bg-blue-500 text-white shadow-inner mt-12">
    <!-- Section principale -->
    <div class="container px-4 py-12 mx-auto">
        <div class="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-4">

            <!-- Informations du shop -->
            <div class="space-y-3">
                <h3 class="text-xl font-bold text-white">
                    {{ $shop->name }}
                </h3>
                <div class="space-y-2 text-sm text-blue-100">
                    <p class="flex items-start gap-2">
                        <x-icon name="o-map-pin" class="w-5 h-5 mt-0.5 text-blue-200 shrink-0" />
                        <span>{{ $shop->address }}</span>
                    </p>
                    <p class="flex items-center gap-2">
                        <x-icon name="o-phone" class="w-5 h-5 text-blue-200 shrink-0" />
                        <a href="tel:{{ $shop->phone }}" class="hover:text-white transition-colors">
                            {{ $shop->phone }}
                        </a>
                    </p>
                    <p class="flex items-center gap-2">
                        <x-icon name="o-envelope" class="w-5 h-5 text-blue-200 shrink-0" />
                        <a href="mailto:{{ $shop->email }}" class="hover:text-white transition-colors">
                            {{ $shop->email }}
                        </a>
                    </p>
                </div>
            </div>

            <!-- Liens légaux -->
            <div>
                <h6 class="mb-4 text-xs font-bold tracking-wider uppercase text-blue-200">
                    {{ __('Informations légales') }}
                </h6>
                <ul class="space-y-2 text-sm">
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Mentions légales') }}
                        </a>
                    </li>
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Conditions générales de vente') }}
                        </a>
                    </li>
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Politique de confidentialité') }}
                        </a>
                    </li>
                </ul>
            </div>

            <!-- Services -->
            <div>
                <h6 class="mb-4 text-xs font-bold tracking-wider uppercase text-blue-200">
                    {{ __('Services & Infos') }}
                </h6>
                <ul class="space-y-2 text-sm">
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Livraisons') }}
                        </a>
                    </li>
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Respect de l\'environnement') }}
                        </a>
                    </li>
                    <li>
                        <a href="/"
                           class="text-blue-100 hover:text-white transition-colors hover:underline">
                            {{ __('Mandat administratif') }}
                        </a>
                    </li>
                </ul>
            </div>

            <!-- Réseaux sociaux & Newsletter -->
            <div>
                <h6 class="mb-4 text-xs font-bold tracking-wider uppercase text-blue-200">
                    {{ __('Suivez-nous') }}
                </h6>

                <!-- Réseaux sociaux avec fond légèrement contrasté -->
                <div class="flex items-center gap-2 mb-6">
                    @if($shop->facebook)
                        <a href="{{ $shop->facebook }}"
                           target="_blank"
                           rel="noopener noreferrer"
                           class="btn btn-circle btn-ghost btn-sm bg-white/10 hover:bg-white/20 text-white">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" class="fill-current">
                                <path d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z"/>
                            </svg>
                        </a>
                    @endif

                    @if($shop->linkedin ?? false)
                        <a href="{{ $shop->linkedin }}"
                           target="_blank"
                           rel="noopener noreferrer"
                           class="btn btn-circle btn-ghost btn-sm bg-white/10 hover:bg-white/20 text-white">
                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" class="fill-current">
                                <path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
                            </svg>
                        </a>
                    @endif
                </div>

                <!-- Newsletter -->
                <div class="space-y-2">
                    <p class="text-xs text-blue-200 font-semibold uppercase tracking-wider">
                        {{ __('Newsletter') }}
                    </p>
                    <x-button
                        label="{!! __('S\'abonner à la lettre d\'information') !!}"
                        icon-right="o-arrow-top-right-on-square"
                        link="/"
                        external
                        class="bg-white hover:bg-blue-50 text-blue-600 border-none btn-xs font-bold"
                    />
                </div>
            </div>
        </div>
    </div>

    <!-- Copyright -->
    <div class="border-t border-blue-400/30 bg-blue-600/30">
        <div class="container flex flex-col items-center justify-between px-4 py-4 mx-auto text-xs text-blue-100 md:flex-row">
            <span>&copy; {{ date('Y') }} {{ $shop->name }}. {{ __('Tous droits réservés.') }}</span>
        </div>
    </div>
</footer>

On ajoute le code dans le layout app pour charger le footer :

{{-- FOOTER --}}
<footer role="contentinfo" class="mt-auto">
    <livewire:navigation.footer />
</footer>

Et on a notre bas de page :

Les pages

Maintenant, on va s'occuper des pages statiques. On crée un nouveau composant :

php artisan make:livewire pages::page

Avec ce simple code :

<?php

use Livewire\Component;
use App\Models\Page;

new class extends Component {

    public Page $page;

    public function mount(Page $page): void
    {
        $this->page = $page;
    }

}; ?>

<div class="container mx-auto prose max-w-none">
    <x-card title="{!! $this->page->title !!}" class="w-full shadow-md shadow-gray-500" shadow separator >
        {!! $this->page->text !!}
    </x-card>
</div>

On ajoute la route :

Route::livewire('/pages/{page:slug}', 'pages::page')->name('pages');

Dans le footer, on renseigne les routes :

<!-- Liens légaux -->
<div>
    <h6 class="mb-4 text-xs font-bold tracking-wider uppercase text-blue-200">
        {{ __('Informations légales') }}
    </h6>
    <ul class="space-y-2 text-sm">
        <li>
            <a href="{{ route('pages', ['page' => 'mentions-legales']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Mentions légales') }}
            </a>
        </li>
        <li>
            <a href="{{ route('pages', ['page' => 'conditions-generales-de-vente']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Conditions générales de vente') }}
            </a>
        </li>
        <li>
            <a href="{{ route('pages', ['page' => 'politique-de-confidentialite']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Politique de confidentialité') }}
            </a>
        </li>
    </ul>
</div>

<!-- Services -->
<div>
    <h6 class="mb-4 text-xs font-bold tracking-wider uppercase text-blue-200">
        {{ __('Services & Infos') }}
    </h6>
    <ul class="space-y-2 text-sm">
        <li>
            <a href="{{ route('pages', ['page' => 'livraisons']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Livraisons') }}
            </a>
        </li>
        <li>
            <a href="{{ route('pages', ['page' => 'respect-environnement']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Respect de l\'environnement') }}
            </a>
        </li>
        <li>
            <a href="{{ route('pages', ['page' => 'mandat-administratif']) }}"
               class="text-blue-100 hover:text-white transition-colors hover:underline">
                {{ __('Mandat administratif') }}
            </a>
        </li>
    </ul>
</div>

Les liens du footer (liens légaux et services) doivent désormais fonctionner.

Conclusion

Dans ce chapitre, on a mis en place notre page d'accueil avec la navigation (barre supérieure, barre latérale et footer). On dispose d'une vignette pour chaque produit avec son image, son prix et sa description. Pour le moment les liens ne fonctionnent pas. Je n'ai pas prévu de pagination en cas de nombreux produits, mais c'est facile à ajouter. On va partir du principe qu'on a une petite boutique avec peu de produits.



    Par bestmomo

    Aucun commentaire

    Article précédent : Shop V2 : les données 2/2