Added products.show page

This commit is contained in:
Noah Lancien 2023-10-30 17:31:15 +01:00
parent aba83a5c91
commit a65d855acc
18 changed files with 476 additions and 13 deletions

View file

@ -24,4 +24,47 @@ enum CookingModeEnum: int
self::pan->name => 'Poêle',
self::fresh->name => 'Se consomme frais',
];
/**
* Pictures paths.
*/
private const PICTURES = [
self::microwave->name => 'resources/assets/images/pictos/micro-wave.png',
self::furnace->name => 'resources/assets/images/pictos/furnace.png',
self::waterbath->name => 'resources/assets/images/pictos/water-bath.png',
self::pan->name => 'resources/assets/images/pictos/pan.png',
self::fresh->name => 'resources/assets/images/pictos/fresh.png',
];
/**
* Get picture path
*
* @return string
*/
public function picture(): string
{
return self::PICTURES[$this->name];
}
/**
* Alt attributes for pictures.
*/
private const ALTS = [
self::microwave->name => 'Pictogramme d\'un micro-ondes',
self::furnace->name => 'Pictogramme d\'un four traditionnel',
self::waterbath->name => 'Pictogramme d\'un bain-marie',
self::pan->name => 'Pictogramme d\'une poêle',
self::fresh->name => 'Pictogramme d\'une goutte d\'eau',
];
/**
* Get picture alt attribute
*
* @return string
*/
public function alt(): string
{
return self::ALTS[$this->name];
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\Product;
class ProductController extends Controller
{
/**
* Display the product page.
*
* @param \App\Models\Product $product
* @return \Illuminate\Contracts\View\View
*/
public function show(Product $product): \Illuminate\Contracts\View\View
{
$otherProductModels = $product->range->products()
->where('id', '!=', $product->id)
->where('published', true)
->inRandomOrder()
->get();
return view('fo.pages.products.show', compact('product', 'otherProductModels'));
}
}

View file

@ -64,6 +64,11 @@ class RouteServiceProvider extends ServiceProvider
Route::model('convictionpage', Convictionpage::class);
Route::model('joinuspage', Joinuspage::class);
Route::model('testimonial', Testimonial::class);
// * FRONT
Route::bind('publishedProduct', function ($value) {
return Product::where('slug', $value)->where('published', true)->firstOrFail();
});
}
/**

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Calque_2" data-name="Calque 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 375 702.01">
<defs>
<style>
.cls-1 {
fill: #f1f1f1;
}
</style>
</defs>
<g id="homepage">
<path class="cls-1" d="M375,2.3c-3.11,9.14-6.52-9.88-8.44,6.92-.67-2.98-1.5-5.31-2.74-4.3-1.73,.75-4.62-1.88-6.39,1.96-3.27-1.6-7.06-1.66-10.34-.17-3.27,.21-6.31-.87-9.74,.88-.22-1.04-.75-1.56-.6-3.1-3.27,2.53-5.94,.16-9.43,.88-.76,6.82-2.07-.29-3.35,2.01-1.39-3.89-3.42-1.34-5.18-2.14-1.51,6.55-3.79-2.38-5.79,1.97-1.87-5.45-4.1,1.87-6.09-1.13-1.58,3.97-3.42-3.41-4.85,2.11-1.53-5.57-3.58,4.07-5.18-2.27-1.66,1.78-2.89-.05-4.55,2.12-1.46-4.28-3.2,4.07-4.24-3.29-2.52,2.54-4.66-1.11-7.03,3.11-.75-.66-1.73,1.26-2.1-2.22-.87,5.53-2.37-1.84-3.05,2.14-3.87-4.31-9.06-.79-12.77-3.43-1.02,2.05-2.52,3.18-3.35,3.17-1.09-1.44-1.62,2.04-2.45,3.05-.59-8.13-2.82,2.79-2.73-6.36l-1.21,2.04c-2.36-3.13-5.86-3.19-8.23-.13-5.07-1.89-10.94-.95-15.82-1.28-1.43,3.97-3.04-3.4-4.25,2.12-1.76-5.31-3.13,5.62-4.59-.07-.15-1.68,.42-2.19,.64-3.21-.94-.27-1.77,.23-2.45,2.02-1.92,.23-4.24-5.48-5.79,1.07-2.97-1.21-5.86-2.28-8.83-3.36-2.41,3.19-5-1.63-7.29-.12-1.64-9.18-3.58,3.68-5.49,4.17-.52-1.94-1.8-1.7-1.5-5.31l-3.05,.98c-1.99-1.58-3.81,7.8-5.49-.09-.75-.27-1.73-.03-1.81,3.19l-.94-3.24c-.53-.78-.75,1.28-1.2,1.01-3.42-3.15-7.07,1.43-10.34-.16-1.68-8.79-3.21,8.84-4.58-3.17-.68-.01-1.43-.54-1.81,2.03-1.24,.24-2.45,3.96-3.65,.97-2.6,3.18-5.71-1.9-8.53,2.05-1.04-5.3-1.77,.75-2.75,2.02-1.72-6.6-4.33,4.06-6.39-2.16-.89-10.19-3.2,2.79-5.19,.95-2.24-10.47-5.68,2.49-8.79-3.36-2.68,6.02-6.08-3.45-8.54,4.12-.6,.25-1.13-.28-1.5-2.08-2.44-3.52-5.27,2.24-7.33-1.28-1.81,2.68-4.4-1.1-6.09,3.13-.6,1.28-1.96,2.29-2.4-1.07,0-1.03-.07-2.71,.31-3.22-1.69-.03-2.9,3.95-4.59,4.18-.9-2.72-1.87-4.02-3.04-4.3-1.74,6.55-3.26-3.92-5.15,.95-2.73-6.23-5.49,3.13-8.23-.13-1.88-1.83-.91,7.07-2.75,6.27-1.27-9.17-4.62-4.46-6.68-4.23-2.19,7.44-3.49-5.6-6.09-1.13-1.66,6.93-2.4-5.84-4.25-.07-1.49-6.34-2.67,3.05-4.55-.07-3.75-4.06-8.31,3.22-12.17-2.39-1.78,7.32-4.25-1.1-6.39,3.12-1.84-3.51-3.65,2.26-5.49-1.12-2.15,6.15-4.02-4.06-6.39,.93-2.14-4.8-3.65,4.58-5.79-.09-1.21,3.59-3.49-2.51-4.85,.95-1.41,4.19-4.25-4.2-5.35,3.21h-.22c-.53-6.82-1.67-.85-2.88-.06h-.34c-.11-.05-.23-.02-.34-.2-.52-.78-.22-2.84-.29-4.13-1.29-.91-2.6-.8-3.91-.35V698.27s.04,.02,.06,.02c1.99-2.03,3.5-.2,5.49-1.97,3.87,2.9,8.53-.64,12.78-.83,2.14,.81,4.09,3.42,6.09,.1,3.12-.72,6.38,3.71,10.03,2.22,.91-4.5,2.07-1,3.05-2.02,2.1,3.39,5.22,2.41,7.59,1.15l.3,1.04c4.82-3.28,9.51,2.47,14.32-.81,2.25,.29,5.86-.68,7.89,1.16,2.07-.74,5.26,1.89,7.29-1.95,3.83,3.93,9.51,1.44,13.72,2.28,1.81-2.03,4.17,1.87,6.09-.93,1.96-.48,3.8,.57,5.45,3.18,1.01,.27,2.82-.73,3.98,1.09,.53-5.15,2.18-1.51,3.05-4.08,.98-1.53,1.57,3.12,2.41,.04,2.14,4.42,4.22-4.44,6.09,1.13,1.55-3.07,3.64,1.61,5.79,.09,1.06-4.75,2.44,1.33,3.65-2.01,3.11,4.18,6.32-3.64,9.13,1.18,1.99,1.83,3.8-3.94,5.49,1.12l7.6-2.97c.67,1.82,1.27,2.08,2.14,1.06,1.05,3.37,3.04,2.37,4.25,1.1,.52,1.3,1.13,1.05,1.54-1.01,1.95,1.58,4.4,1.62,6.39,.1,4.47,1.62,10.71,1.72,15.18,.24,3.98,5.48,7.56-1.69,11.27,2.24,1.73-3.32,4.4-2.25,6.39-.93,.91-5.53,2.18,1.84,3.35-2.01,1.79,7.25,3.5-5.49,5.15,1.11,1.47-6.29,2.36,4.68,4.28,1.1,3.5-3.94,8.19,1.68,11.84-3.03,2.44,3,5.04-.95,7.33,.12,2.82,1.98,7.07,1.02,10.03,1.32,2.07-.74,5.26,1.89,7.29-2.07,1.31,6.85,3.34,.31,5.18,2.27,1.14-5.52,2.67,1.85,3.95-2.13,1.54,3.51,4.02,2.51,5.79,1.12h.6c5.11,1.51,9.59-1.9,14.28,2.43,2.68-6.53,5.11,3.95,7.93-.91,1.14-7.07,2.89,.31,4.55-2.12,1.69,3.51,4.28,2.52,6.09,1.13,1.39,.67,3.11,4.04,4.28,.07,2.02,3.51,4.4-2.25,6.05,1.26,5.79-.16,11.58-3.81,17.37-.88,2-3.58,3.79,1.73,5.49-1.97,.75,4.78,2.97-.73,3.05-2.02-.78-3.62,2.9-2.38,2.8-3.39l24.88,3.18c.57,.58,4.56-2.37,4.56-2.37-.08,2.84-1.02,2.82-1.55,4.1,3.04,3.53,6.09-2.22,9.13,1.17,1.91,4.03,4.17-1.22,6.39-.93,.13,.2,.27,.39,.4,.56V2.3Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Calque_2" data-name="Calque 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 197.8 25.63">
<defs>
<style>
.cls-1 {
fill: #A9C27E;
stroke-width: 0px;
}
</style>
</defs>
<g id="une_actualité" data-name="une actualité">
<path class="cls-1" d="m176.87,25.22c.62,0,1.25,0,1.87,0,3.35.01,6.69.03,10.04.04,1.35,0,4.13.78,5.34.03,1.84-1.13.11-1.03,1.07-3.15.4-.9,2.08-10.88.33-15.46.76.05.84-1.64.75-2.9-.09-1.26.93-1.92,1.53-3.74-53.8.05-107.6.11-161.4.16C89.5.14,142.6.07,195.7,0,131.54,0,22.9.2,32.74.3,22.06-.28,11.35.04.7,1.25c.25,6.26-1.25,17.27-.46,17.4s.97,1.64.72,2.67-.73,2.09-.5,3.14c39.36.17,78.72.34,118.07.51,13.38.06,26.76.11,40.15.17,6.07.03,12.13.05,18.2.08Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -20,3 +20,4 @@
@import './pages/ranges';
@import './pages/contact';
@import './pages/explorerpage';
@import './pages/product';

View file

@ -261,19 +261,6 @@
// MMMMMMMM MMMMMMMMDDDDDDDDDDDDD
@include media-breakpoint-up(md) {
.explorerpage {
.title-card {
.adjectives {
// .f-sheldon {
// font-size: 5rem !important;
// }
// .leaf-picture {
// width: 3rem;
// height: 3rem;
// }
}
}
.passion {
.second-paragraph {
font-size: 2rem;

View file

@ -0,0 +1,147 @@
.product {
.text-justify {
hyphens: auto;
text-align: justify;
}
.title-card {
.pictures {
background-image: url('@/images/global/bg-white-desktop.png');
background-position: center;
background-repeat: no-repeat;
background-size: 100% 90%;
}
}
.cooking {
.green-title {
background-image: url('@/images/global/bg-title-green.svg');
background-position: left bottom;
background-repeat: no-repeat;
background-size: 100%;
}
table {
tr {
th {
border-width: 3px;
border-color: #fff;
border-top: 0;
}
td {
border-width: 3px;
border-color: #fff;
border-bottom: 0;
}
:first-child {
border-left: 0;
}
:last-child {
border-right: 0;
}
&:last-child {
border-bottom: 0;
}
}
}
.picto-img {
width: 35%;
}
}
.swiper-product-pictures,
.swiper-other-products {
.swiper-button {
&-prev,
&-next { width: 3rem; }
&-next { rotate: 180deg; }
&-disabled { opacity: .5; }
}
}
.discover {
.other-products {
background-image: url('@/images/global/bg-white-desktop.png');
background-position: center;
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
}
@include media-breakpoint-up(lg) {
.product {
.title-card {
.pictures {
background-size: 85% 85%;
}
}
}
}
// XXXXXXX XXXXXXXLLLLLLLLLLL
// X:::::X X:::::XL:::::::::L
// X:::::X X:::::XL:::::::::L
// X::::::X X::::::XLL:::::::LL
// XXX:::::X X:::::XXX L:::::L
// X:::::X X:::::X L:::::L
// X:::::X:::::X L:::::L
// X:::::::::X L:::::L
// X:::::::::X L:::::L
// X:::::X:::::X L:::::L
// X:::::X X:::::X L:::::L
// XXX:::::X X:::::XXX L:::::L LLLLLL
// X::::::X X::::::XLL:::::::LLLLLLLLL:::::L
// X:::::X X:::::XL::::::::::::::::::::::L
// X:::::X X:::::XL::::::::::::::::::::::L
// XXXXXXX XXXXXXXLLLLLLLLLLLLLLLLLLLLLLLL
@include media-breakpoint-up(xl) {
.product {
.title-card {
.pictures {
background-size: 95% 85%;
}
}
.text-justify {
hyphens: inherit;
text-align: inherit;
}
.cooking {
.green-title {
background-size: 100% !important;
}
}
.discover {
.swiper-other-products {
position: static;
margin: 0 4rem;
.swiper-slide-content {
width: 100%;
}
.navigation {
position: absolute;
top: 50%;
left: 0;
width: 100%;
transform: translateY(-50%);
}
}
.other-products {
background-size: 95% 100%;
}
}
}
}

View file

@ -81,6 +81,35 @@ document.addEventListener("DOMContentLoaded", function () {
},
},
},
"swiper-product-pictures": {
modules: [Navigation],
grabCursor: true,
slidesPerView: 1,
spaceBetween: 60,
// Navigation arrows
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
}
},
"swiper-other-products": {
modules: [Navigation],
grabCursor: true,
slidesPerView: 1,
spaceBetween: 60,
// Navigation arrows
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
breakpoints: {
// when window width is >= 576px
576: {
slidesPerView: 2,
spaceBetween: 0,
},
},
},
};
type SwiperSlider = {
element: HTMLElement;

View file

@ -0,0 +1,182 @@
@extends('fo.layout')
@section('title', $product->seo_title ?? __('Fiche produit'))
@section('description', $product->seo_description ?? __('Fiche descriptive d\'un produit'))
@section('breadcrumb',
request()->route()->getName())
@section('content')
<section class="product col-12 overflow-hidden">
<!-- TITLE CARD -->
<section class="title-card container-fluid position-relative overflow-hidden">
<img class="position-absolute top-50 start-50 translate-middle w-100 h-100 z-n1"
src="{{ Vite::asset('resources/assets/images/global/bg-grey-desktop.png') }}" title="{{ __('Visuel servant de fond') }}"
alt="{{ __('fond gris') }}">
<div class="py-2 px-3 px-lg-5 text-center lh-sm">
<span class="divide d-block w-100 mt-lg-5 mb-3 mt-4"></span>
<h1 class="fs-1 f-sheldon text-uppercase">
{{ $product->title }}
</h1>
<span class="divide d-block w-100 mt-lg-3 mb-1 mb-md-4 mt-3"></span>
</div>
{{-- CARROUSEL image ambiance/packshot --}}
<div class="pictures mb-4 px-5">
<div class="swiper swiper-product-pictures overflow-hidden pb-3 h-100 d-lg-none" id="swiper-product-pictures">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div class="swiper-slide-content d-flex justify-content-center align-items-center mx-auto px-3">
<img src="{{ asset($product->picture_ambiance) }}"
title="{{ $product->picture_ambiance_title }}" alt="{{ $product->picture_ambiance_alt }}">
</div>
</div>
<div class="swiper-slide h-auto">
<div class="swiper-slide-content d-flex justify-content-center align-items-center mx-auto px-3 h-100">
<img src="{{ asset($product->picture_packshot) }}"
title="{{ $product->picture_packshot_title }}" alt="{{ $product->picture_packshot_alt }}">
</div>
</div>
</div>
<div class="d-flex justify-content-evenly align-items-center d-lg-none pb-4 mt-4 flex-row">
<div class="swiper-button-prev rounded-circle" role="button">
<img src="{{ Vite::asset('resources/assets/images/global/btn-arrow.png') }}"
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</div>
<div class="swiper-button-next rounded-circle" role="button">
<img src="{{ Vite::asset('resources/assets/images/global/btn-arrow.png') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</div>
</div>
</div>
<div class="d-none d-lg-flex justify-content-center ms-5 ps-5 pe-3 pb-5">
<img src="{{ asset($product->picture_ambiance) }}"
title="{{ $product->picture_ambiance_title }}"
alt="{{ $product->picture_ambiance_alt }}"
class="h-100 col-8 pb-5">
<img src="{{ asset($product->picture_packshot) }}"
title="{{ $product->picture_packshot_title }}"
alt="{{ $product->picture_packshot_alt }}"
class="h-100 col-4 pb-5 ms-4 mt-auto">
</div>
</div>
{{-- DESCRIPTION --}}
<div class="text-justify text-lg-center col-12 col-lg-9 px-3 mx-lg-auto">{!! clean($product->description) !!}</div>
{{-- PICTOS --}}
@if (!empty($product->commitments))
<div class="pictos px-3 pb-5 col-12 col-lg-8 mx-auto">
<span class="divide d-block w-100 mt-lg-5 mb-2 mb-lg-4 mt-4"></span>
<div class="row justify-content-center px-lg-4">
@foreach ($product->commitments as $commitment)
<div class="col-3">
<div class="w-100 d-flex justify-content-center">
<img src="{{ asset($commitment->picture) }}"
alt="{{ $commitment->picture_alt }}"
title="{{ $commitment->picture_title }}">
</div>
</div>
@endforeach
</div>
<span class="divide d-block w-100 mt-lg-4 mb-3 mt-2"></span>
</div>
@endif
</section>
<section class="cooking container-fluid my-5">
<div class="row px-3">
<div class="col-12 col-lg-6">
{{-- COOKING ADVICE --}}
<h2 class="green-title f-readex-pro text-white fs-6 px-4 py-2 w-100">{{ __('Conseils de Réchauffage') }}</h2>
<div class="col-12 mt-4">
<img src="{{ Vite::asset($product->cooking_mode->picture()) }}"
alt="{{ $product->cooking_mode->alt() }}"
title="{{ $product->cooking_mode->label() }}"
class="picto-img float-start me-3 mt-3">
<div class="text-justify">{!! clean($product->cooking_advice) !!}</div>
</div>
{{-- INGREDIENTS --}}
<h2 class="green-title f-readex-pro text-white fs-6 px-4 py-2 w-100 mt-5">{{ __('Ingrédients') }}</h2>
<div class="col-12">
<div class="text-justify">{!! clean($product->ingredients) !!}</div>
</div>
</div>
<div class="col-12 col-lg-6 h-auto">
<div class="h-100 d-flex flex-column justify-content-between">
<div class="h-50 d-none d-lg-flex align-items-center">
<img src="{{ Vite::asset('resources/assets/images/products/leafs-and-seeds.png') }}"
alt="Dessins de feuilles et de graines éparpillées"
title="Décoration fiche produit">
</div>
{{-- NUTRITIONNAL VALUES --}}
@php
$nutrionnal_values = json_decode($product->nutritionnal_values);
@endphp
<table class="table table-bordered mt-4 f-readex-pro">
<thead>
<tr class="table-dark">
<th class="text-uppercase text-white ps-sm-5 py-xl-3">{{ __('Valeurs nutritionnelles') }}</th>
<th class="text-white text-center py-xl-3"><span class="text-uppercase">{{ __('POUR') }}</span> {{ __('100g') }}</th>
</tr>
</thead>
<tbody>
@foreach ($nutrionnal_values as $line)
<tr class="table-secondary">
<td class="text-dark ps-sm-5">{{ $line->label }}</td>
<td class="text-dark text-center">{{ $line->value }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</section>
@if (count($otherProductModels))
<section class="discover container-fluid position-relative py-5 mb-4">
<img class="position-absolute top-50 start-50 translate-middle w-100 h-100 z-n1"
src="{{ Vite::asset('resources/assets/images/global/bg-grey-desktop.png') }}" title="{{ __('Visuel servant de fond') }}"
alt="{{ __('fond gris') }}">
<h2 class="text-primary text-uppercase f-sheldon text-center w-100 pt-3 pt-xl-4 mb-5">
{{ __('Découvrez nos produits') }}
</h2>
{{-- CARROUSEL produits même gamme mais ordre aléatoire --}}
<div class="other-products px-3 px-xl-5 mx-xl-5">
<div class="swiper swiper-other-products overflow-hidden w-xl-100 mx-xl-0" id="swiper-other-products">
<div class="swiper-wrapper">
@foreach ($otherProductModels as $otherProduct)
<div class="swiper-slide">
<div class="swiper-slide-content d-flex flex-column justify-content-center align-items-center mx-auto px-3 pt-5 pb-xl-5 w-xl-75">
<img src="{{ asset($otherProduct->picture_ambiance) }}"
title="{{ $otherProduct->picture_ambiance_title }}"
alt="{{ $otherProduct->picture_ambiance_alt }}"
class="">
<div class="w-100 d-xl-none">
<a class="w-fit" href="{{ route('fo.products.show', ['publishedProduct' => $otherProduct]) }}">{{ __('> En savoir +') }}</a>
</div>
</div>
</div>
@endforeach
</div>
@if (count($otherProductModels) > 1)
<div class="navigation d-flex justify-content-evenly justify-content-xl-between align-items-center p-xl-4 mb-2 mt-3 flex-row p-0">
<div class="swiper-button-prev rounded-circle" role="button">
<img src="{{ Vite::asset('resources/assets/images/global/btn-arrow.png') }}"
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</div>
<div class="swiper-button-next rounded-circle" role="button">
<img src="{{ Vite::asset('resources/assets/images/global/btn-arrow.png') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</div>
</div>
@endif
</div>
</div>
<div class="pb-4">
<a class="btn btn-primary d-none d-xl-block mx-auto my-4 w-fit" href="#">{{ __('> Voir toutes nos gammes') }}</a>
</div>
</section>
@endif
</section>
@endsection

View file

@ -1,6 +1,7 @@
<?php
use App\Http\Controllers\Fo\RangeController;
use App\Http\Controllers\Fo\ProductController;
use App\Http\Controllers\Fo\StaticPageController;
use Illuminate\Support\Facades\Route;
@ -15,6 +16,9 @@ Route::middleware(['throttle:credentials'])
Route::get('/gammes', [RangeController::class, 'index'])->name('ranges.index');
Route::get('/gammes/{slug}', [RangeController::class, 'show'])->name('ranges.show');
// * products
Route::get('/produits/{publishedProduct:slug}', [ProductController::class, 'show'])->name('products.show');
// * CONTACT
Route::get('/contact', [StaticPageController::class, 'contact'])->name('contact.show');
Route::post('/contact-form', [StaticPageController::class, 'contactForm'])->name('contact.store');