feat: ✨ add sticky on site page

This commit is contained in:
Corentin Huet 2026-03-05 11:51:15 +01:00
parent 6e6757cd77
commit 93a5181b4d
9 changed files with 187 additions and 0 deletions

View file

@ -65,6 +65,8 @@ class StoreSiteRequest extends FormRequest
'highlights' => 'nullable|string|min:15',
'latitude' => 'required|numeric|between:-90,90',
'longitude' => 'required|numeric|between:-180,180',
'sticky_title' => 'required_with:sticky_link|nullable|string|between:3,255',
'sticky_link' => 'required_with:sticky_title|nullable|string|between:3,255',
'logo_alt' => 'required|string|between:3,255',
'logo_title' => 'required|string|between:3,255',
'picture_1_alt' => 'required|string|between:3,255',
@ -115,6 +117,8 @@ class StoreSiteRequest extends FormRequest
'highlights' => Str::plural(trans('validation.custom.highlight')),
'latitude' => trans('validation.custom.latitude'),
'longitude' => trans('validation.custom.longitude'),
'sticky_title' => trans('validation.custom.sticky_item.title'),
'sticky_link' => trans('validation.custom.sticky_item.link'),
'logos' => Str::plural(trans('models.classes.logo')),
'logos.*' => trans('models.classes.logo'),
'logo_alt' => trans(':field :inter:model', [

View file

@ -81,6 +81,8 @@ class Site extends Model implements Sitemapable
'highlights',
'latitude',
'longitude',
'sticky_title',
'sticky_link',
'logo',
'logo_alt',
'logo_title',

View file

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('sites', function (Blueprint $table) {
$table->string('sticky_title')->nullable()->comment('Sticky item title')->after('longitude');
$table->string('sticky_link')->nullable()->comment('Sticky item link')->after('sticky_title');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('sites', function (Blueprint $table) {
$table->dropColumn('sticky_title');
$table->dropColumn('sticky_link');
});
}
};

View file

@ -296,5 +296,9 @@ return [
'message' => 'message',
'banner' => 'bannière',
'subtitle' => 'sous-titre',
'sticky_item' => [
'title' => 'titre de l\'ancre',
'link' => 'lien de l\'ancre',
],
],
];

View file

@ -20,4 +20,45 @@
}
}
}
.site-navigation {
@include media-breakpoint-up(md) {
position: fixed;
z-index: 10;
bottom: 4rem;
left: 4rem;
max-width: 15rem;
&-wrapper {
height: 0;
opacity: 0;
transform: translateY(25%);
transition: .3s;
visibility: hidden;
&.show {
height: auto;
opacity: 1;
transform: translateY(0);
visibility: visible;
}
}
}
.col-md-12 {
@include media-breakpoint-up(md) {
width: fit-content;
}
.badge {
width: .5rem;
height: .5rem;
@include media-breakpoint-up(md) {
width: 1rem;
height: 1rem;
}
}
}
}
}

View file

@ -21,4 +21,5 @@ import "./base/layout";
// PAGES
import "./pages/commitments";
import "./pages/unveil";
import "./pages/site";

View file

@ -0,0 +1,17 @@
document.addEventListener("DOMContentLoaded", function () {
const site = document.querySelector("section.site");
if (site === null) {
return;
}
const button = document.querySelector(".site-navigation .btn") as HTMLButtonElement;
const navWrapper = document.querySelectorAll(".site-navigation-wrapper ");
button.addEventListener("click", () => {
navWrapper.forEach((element: Element) => {
element.classList.toggle("show");
});
document.querySelectorAll(".site-navigation .btn svg").forEach(icon => {
icon.classList.toggle("d-none");
});
});
});

View file

@ -532,6 +532,72 @@
</div>
</fieldset>
</div>
{{-- STICKY --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">
<legend>{{ Str::ucfirst(trans_choice('validation.custom.sticky', 0)) }}</legend>
<div class="row mb-3">
{{-- STICKY_TITLE --}}
<div class="col-12 col-md-6 m-md-0 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'siteStickyTitle',
'label' => __(':field :inter :model', [
'field' => Str::ucfirst(__('validation.custom.sticky_item.title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
'hasWordCounter' => true,
'name' => 'sticky_title',
'required' => false,
'model' => $siteModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.custom.sticky_item.title'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __(':field :inter :model', [
'field' => Str::ucfirst(__('validation.custom.sticky_item.title')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
])
</div>
{{-- STICKY_LINK --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'siteStickyLink',
'label' => __(':field :inter :model', [
'field' => Str::ucfirst(__('validation.custom.sticky_item.link')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
'hasWordCounter' => true,
'name' => 'sticky_link',
'required' => false,
'model' => $siteModel ?? null,
'helper' => __('validation.between.string', [
'attribute' => __(':field :inter:model', [
'field' => __('validation.custom.sticky_item.link'),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
'min' => 3,
'max' => 255,
]),
'placeholder' => __(':field :inter :model', [
'field' => Str::ucfirst(__('validation.custom.sticky_item.link')),
'inter' => __('validation.custom.of_the.male'),
'model' => trans_choice('models.classes.site', 1),
]),
])
</div>
</div>
</fieldset>
</div>
{{-- LOGO --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">

View file

@ -6,6 +6,28 @@
@section('content')
<section class="site">
@if ($siteModel->sticky_title && $siteModel->sticky_link)
<div class="site-navigation z-2">
<div class="site-navigation-wrapper show row m-0 p-0">
<div class="col-6 col-md-12 px-md-0 py-md-1 p-2">
<div class="rounded-5 bg-quad-light shadow-sm">
<a class="d-flex justify-content-center align-items-center text-primary text-decoration-none p-sm-3 p-2"
data-bs-toggle="tooltip" href="{{ $siteModel->sticky_link }}"
target="_blank" rel="noopener noreferrer"
title="{{ __('Accéder au site :name', ['name' => $siteModel->sticky_title]) }}">
<span class="badge rounded-pill bg-quad d-block me-2"></span>
<small>{{ $siteModel->sticky_title }}</small>
</a>
</div>
</div>
</div>
<button class="d-none d-md-block btn btn-primary rounded-pill mt-1 w-fit px-3"
title="{{ __('Afficher/Masquer le menu des ancres') }}">
<i class="fa-solid fa-plus d-none"></i>
<i class="fa-solid fa-minus"></i>
</button>
</div>
@endif
<section class="header container">
<div class="row justify-content-center">
<div class="col-6 col-sm-6 col-md-4 col-lg-3">