fix: 🐛 add missing arrows to the slider, add component for ordering carousels

This commit is contained in:
Corentin Huet 2026-03-30 09:49:40 +02:00
parent cfffe97e06
commit 3a4ec13798
11 changed files with 116 additions and 60 deletions

View file

@ -8,6 +8,8 @@ use App\Http\Requests\Bo\Carousels\UpdateCarouselRequest;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Carousel;
use App\Models\Section;
use App\Traits\Controllers\UpdateModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
@ -15,6 +17,9 @@ use Illuminate\Support\Str;
class CarouselController extends Controller
{
use UpdateModelOrder;
use UpdateModelPublished;
/**
* Create the controller instance.
*/

View file

@ -278,7 +278,7 @@ class StaticPageController extends Controller
$testimonialSection = $sectionModels->where('section', PageSectionEnum::hire_grow)->first();
$paritySection = $sectionModels->where('section', PageSectionEnum::hire_parity)->first();
$findSection = $sectionModels->where('section', PageSectionEnum::hire_find)->first();
$carouselSectionParity = Carousel::query()->where('section_id', PageSectionEnum::hire_parity)->where('published', true)->get();
$carouselSectionParity = Carousel::query()->where('section_id', PageSectionEnum::hire_parity)->where('published', true)->orderBy('order')->get();
$navLinks = Sticky::query()->where('type', StaticPageType::we_hire)->get();
return view('fo.pages.hire', \compact(

View file

@ -5,6 +5,7 @@ namespace App\Models;
use App\Lib\Helpers\FileStorageHelper;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use App\Traits\Models\Orderable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -21,6 +22,7 @@ class Carousel extends Model
{
use ActivityLog;
use HasFactory;
use Orderable;
/**
* The attributes that are mass assignable.
@ -78,28 +80,14 @@ class Carousel extends Model
// * METHODS
/**
* Set order after the last element of the list.
* Group ordering by section_id.
*
* @param self $model
* @param boolean $isDeletion
* @return void
* @return string
*/
private static function setOrder(self $model, bool $isDeletion = false): void
public function getOrderGroupField(): string
{
$maxOrder = \intval(self::query()->where('section_id', $model->section_id)->max('order'));
if ($isDeletion) {
$request = Carousel::query()
->where('section_id', $model->section_id)
->whereNot('id', $model->id)
->whereBetween('order', [$model->order, $maxOrder]);
$request->decrement('order', 1);
return;
}
$model->order = $maxOrder + 1;
return 'section_id';
}

View file

@ -5,6 +5,7 @@ namespace App\Providers;
use App\Http\Middleware\VerifyCsrfToken;
use App\Models\Aisle;
use App\Models\Brand;
use App\Models\Carousel;
use App\Models\Network;
use App\Models\News;
use App\Models\Strip;
@ -53,6 +54,7 @@ class RouteServiceProvider extends ServiceProvider
Route::model('network', Network::class);
Route::model('aisle', Aisle::class);
Route::model('brand', Brand::class);
Route::model('carousel', Carousel::class);
Route::bind('publishedNews', function ($value) {
return News::where(function ($q) use ($value) {
$q->where('slug', $value);

View file

@ -346,42 +346,6 @@ document.addEventListener("DOMContentLoaded", function () {
},
},
},
"swiper-carousels": {
modules: [Pagination],
grabCursor: true,
slidesPerView: 1,
spaceBetween: 15,
centeredSlides: true,
initialSlide: 0,
speed: 750,
pagination: {
el: ".swiper-carousels-pagination",
clickable: true,
renderBullet: function (index: number, className: string) {
return "<button class=\"btn btn-tertiary rounded-0 border-0 w-100 mx-2 p-0 " + className + "\" title=\"Aller à la slide " + (index + 1) + "\"></button>";
},
},
breakpoints: {
576: {
slidesPerView: 1.5,
},
768: {
slidesPerView: 2,
},
992: {
slidesPerView: 2.5,
},
},
on: {
beforeInit(swiper: Swiper) {
const slideCount = swiper.el.querySelectorAll(".swiper-slide").length;
if (slideCount !== 2) {
swiper.params.initialSlide = Math.floor(slideCount / 2);
}
}
}
},
};
const swiperVol = document.getElementsByClassName("swiper") as HTMLCollectionOf<HTMLElement>;

View file

@ -22,4 +22,5 @@ import "./base/sticky";
// PAGES
import "./pages/unveil";
import "./pages/site";
import "./pages/hire";

View file

@ -0,0 +1,63 @@
import Swiper from "swiper";
import { Navigation, Pagination } from "swiper/modules";
document.addEventListener("DOMContentLoaded", function () {
const hire = document.querySelector("section.we-hire");
if (hire === null) {
return;
}
const swiperContainers = document.querySelectorAll(".swiper-container");
swiperContainers.forEach((container, index) => {
const carousel = container.querySelector(".swiper-carousels") as HTMLElement,
btnPrev = container.querySelector(".carousel-prev") as HTMLElement,
btnNext = container.querySelector(".carousel-next") as HTMLElement,
pagination = carousel?.querySelector(".swiper-carousels-pagination") as HTMLElement;
carousel.classList.add(`swiper-${index}`);
pagination.classList.add(`swiper-pagination-${index}`);
btnPrev.classList.add(`prev-${index}`);
btnNext.classList.add(`next-${index}`);
new Swiper(carousel, {
modules: [Pagination, Navigation],
grabCursor: true,
slidesPerView: 1,
spaceBetween: 15,
centeredSlides: true,
initialSlide: 0,
speed: 750,
pagination: {
el: `.swiper-pagination-${index}`,
clickable: true,
renderBullet: function (idx, className) {
return `<button class="btn btn-tertiary rounded-0 border-0 w-100 mx-2 p-0 ${className}" title="Aller à la slide ${idx + 1}"></button>`;
},
},
navigation: {
prevEl: `.prev-${index}`,
nextEl: `.next-${index}`,
},
on: {
beforeInit(swiper: Swiper) {
const slideCount = swiper.el.querySelectorAll(".swiper-slide").length;
if (slideCount !== 2) {
swiper.params.initialSlide = Math.floor(slideCount / 2);
}
},
},
breakpoints: {
576: {
slidesPerView: 1.5
},
768: {
slidesPerView: 2
},
992: {
slidesPerView: 2.5
},
},
});
});
});

View file

@ -12,7 +12,7 @@
@method('PATCH')
<div class="mb-3">
<label for="order-{{ $model->getKey() }}" class="form-label">{{ __('Nouvel ordre') }}</label>
<input type="number" class="form-input" id="order-{{ $model->id }}" placeholder="1" name="order" min="1">
<input type="number" class="form-input" id="order-{{ $model->getKey() }}" placeholder="1" name="order" min="1">
</div>
<button type="submit" class="btn btn-primary">{{ _('Sauvegarder') }}</button>
</form>

View file

@ -1,18 +1,39 @@
<table class="table-hover table-fix-action m-0 table">
@if (count($carouselModels) > 0)
<thead>
@include('bo.modules.table-col-sorter', [
'cols' => [
@php
$cols = [];
if (request()->section) {
$cols = array_merge($cols, [
'order' => Str::ucfirst(__('validation.custom.order')),
]);
}
$cols = array_merge($cols, [
'title' => Str::ucfirst(__('validation.attributes.title')),
'section_id' => Str::ucfirst(trans_choice('models.classes.section', 1)),
'published' => Str::ucfirst(__('validation.custom.activated')),
'updated_at' => Str::ucfirst(__('validation.attributes.updated_at')),
],
]);
@endphp
@include('bo.modules.table-col-sorter', [
$cols
])
</thead>
<tbody>
@foreach ($carouselModels as $carouselModel)
<tr class="border-bottom">
@php
$routeName = request()->route()->getName();
@endphp
@if (request()->section && empty(request()->search) && Session::get("$routeName.sort_col") === 'order')
@include('bo.modules.change-model-order-select', [
'routeName' => 'carousels',
'model' => $carouselModel,
])
@endif
<td class="text-center align-middle">{{ $carouselModel->title }}</td>
<td class="text-center">
<a class="btn btn-sm btn-primary" class="text-center align-middle"

View file

@ -1,6 +1,10 @@
@if (!empty($carousel))
<div class="row">
<div class="col-12 position-relative mb-5">
<div class="col-12 position-relative swiper-container mb-5">
<button class="swiper-button swiper-button-prev-custom carousel-prev z-2">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</button>
<div class="swiper swiper-carousels mt-lg-0 mt-5 overflow-visible" id="swiper-carousels">
<div class="swiper-wrapper h-fit">
@foreach ($carousel->media as $medias)
@ -18,6 +22,10 @@
class="position-relative swiper-pagination swiper-carousels-pagination swiper-pagination-clickable swiper-pagination-bullets swiper-pagination-horizontal d-flex justify-content-center align-items-center mt-5 flex-nowrap px-5">
</div>
</div>
<button class="swiper-button swiper-button-next-custom carousel-next z-2">
<img src="{{ Vite::asset('resources/assets/images/misc/blue-arrow.svg') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</button>
</div>
</div>
@endif

View file

@ -210,6 +210,10 @@ Route::middleware(['admin-secure'])->prefix('bo')
CarouselController::class,
'changePublished'
])->name('carousels.change-published');
Route::patch('/carousels/{carousel}/change-order', [
CarouselController::class,
'changeCustomOrder'
])->name('carousels.change-order');
// * BRANDS
Route::resource('brands', BrandController::class)->except('show')