feat: ✨ allow choosing between picto or image and slow down strip animation by 30%
This commit is contained in:
parent
4b281f8abf
commit
5b74ca5e78
12 changed files with 278 additions and 50 deletions
|
|
@ -9,6 +9,7 @@ use App\Models\News;
|
|||
use App\Models\Strip;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
@ -131,6 +132,15 @@ class StripController extends Controller
|
|||
if ($request->news_id === null) {
|
||||
$strip->news()->dissociate();
|
||||
}
|
||||
|
||||
if (!Arr::exists($request->validated(), 'picture')) {
|
||||
$strip->picture = null;
|
||||
$strip->picture_alt = null;
|
||||
$strip->picture_title = null;
|
||||
} elseif (!Arr::exists($request->validated(), 'picto')) {
|
||||
$strip->picto = null;
|
||||
}
|
||||
|
||||
if ($strip->saveOrFail()) {
|
||||
return redirect()->route('bo.strips.edit', $strip)
|
||||
->with('success', trans('crud.messages.has_been_updated', [
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ class StoreStripRequest extends FormRequest
|
|||
$this->merge([
|
||||
'published' => $this->boolean('published'),
|
||||
]);
|
||||
if ($this->input('picture')) {
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,11 +43,7 @@ class StoreStripRequest extends FormRequest
|
|||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'picto' => [
|
||||
'required',
|
||||
new Enum(\App\Enums\Strips\PictoEnum::class)
|
||||
],
|
||||
$rules = [
|
||||
'text' => [
|
||||
'required',
|
||||
'string',
|
||||
|
|
@ -55,6 +54,29 @@ class StoreStripRequest extends FormRequest
|
|||
'publish_at' => 'nullable|date',
|
||||
'unpublish_at' => 'nullable|date|after:publish_at',
|
||||
];
|
||||
|
||||
if ($this->input('picture')) {
|
||||
$rules = array_merge(
|
||||
$rules,
|
||||
[
|
||||
'picture_alt' => 'required_with|string|between:3,255',
|
||||
'picture_title' => 'required_with|string|between:3,255',
|
||||
],
|
||||
$this->pictureRules('picture', 100, 65, 100, 65, true),
|
||||
);
|
||||
} else {
|
||||
$rules = array_merge(
|
||||
$rules,
|
||||
[
|
||||
'picto' => [
|
||||
'required',
|
||||
new Enum(\App\Enums\Strips\PictoEnum::class)
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -65,12 +87,15 @@ class StoreStripRequest extends FormRequest
|
|||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'picto' => trans('validation.custom.picto'),
|
||||
'text' => trans('validation.attributes.content'),
|
||||
'news_id' => trans('models.classes.news'),
|
||||
'published' => trans('validation.custom.activated'),
|
||||
'publish_at' => trans('validation.custom.publish_at'),
|
||||
'unpublish_at' => trans('validation.custom.unpublish_at'),
|
||||
'picto' => trans('validation.custom.picto'),
|
||||
'picture' => trans('validation.custom.picture'),
|
||||
'picture_alt' => trans('validation.custom.alt_attribute'),
|
||||
'picture_title' => trans('validation.custom.title_attribute'),
|
||||
'text' => trans('validation.attributes.content'),
|
||||
'news_id' => trans('models.classes.news'),
|
||||
'published' => trans('validation.custom.activated'),
|
||||
'publish_at' => trans('validation.custom.publish_at'),
|
||||
'unpublish_at' => trans('validation.custom.unpublish_at'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,23 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\Strips\PictoEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Traits\Models\ActivityLog;
|
||||
use App\Traits\Models\PlanificatedStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property App\Enums\Strips\PictoEnum $picto Picto.
|
||||
* @property string $text WYSIWYG restrained (blod and underline only). Text.
|
||||
* @property boolean $published Publication status.
|
||||
* @property \Carbon\Carbon|null $publish_at Publication date.
|
||||
* @property \Carbon\Carbon|null $unpublish_at Unpublication status update date.
|
||||
* @property-read \Carbon\Carbon $created_at Created date.
|
||||
* @property-read \Carbon\Carbon $updated_at Updated date.
|
||||
* @property App\Enums\Strips\PictoEnum $picto Picto.
|
||||
* @property string $picture Strip picture path.
|
||||
* @property string $picture_alt Strip picture alt attribute.
|
||||
* @property string $picture_title Strip picture title attribute.
|
||||
* @property string $text WYSIWYG restrained (blod and underline only). Text.
|
||||
* @property boolean $published Publication status.
|
||||
* @property \Carbon\Carbon|null $publish_at Publication date.
|
||||
* @property \Carbon\Carbon|null $unpublish_at Unpublication status update date.
|
||||
* @property-read \Carbon\Carbon $created_at Created date.
|
||||
* @property-read \Carbon\Carbon $updated_at Updated date.
|
||||
*
|
||||
* @property-read \App\Models\News $news News Belongs to relationship.
|
||||
* @property-read \App\Models\ActivityLog $activityLogs Activities logs One-to-many relationship.
|
||||
|
|
@ -33,6 +37,9 @@ class Strip extends Model
|
|||
*/
|
||||
protected $fillable = [
|
||||
'picto',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'text',
|
||||
'published',
|
||||
'publish_at',
|
||||
|
|
@ -65,6 +72,12 @@ class Strip extends Model
|
|||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
|
@ -78,6 +91,9 @@ class Strip extends Model
|
|||
private static function manageFields(self $model): void
|
||||
{
|
||||
self::makeStatusSense($model);
|
||||
if ($model->picture) {
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
|
||||
}
|
||||
}
|
||||
|
||||
// * RELATIONS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
<?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('strips', function (Blueprint $table) {
|
||||
$table->string('picto')->nullable()->comment('Picto file path')->change();
|
||||
$table->string('picture')->nullable()->comment('Picture file path')->after('picto');
|
||||
$table->string('picture_title')->nullable()->comment('Picture title')->after('picture');
|
||||
$table->string('picture_alt')->nullable()->comment('Picture alt text')->after('picture_title');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('strips', function (Blueprint $table) {
|
||||
$table->string('picto')->nullable(false)->change();
|
||||
$table->dropColumn('picture');
|
||||
$table->dropColumn('picture_title');
|
||||
$table->dropColumn('picture_alt');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -302,6 +302,7 @@ return [
|
|||
'title' => 'titre de l\'ancre',
|
||||
'link' => 'lien de l\'ancre',
|
||||
],
|
||||
'media' => 'média',
|
||||
'anchor' => 'ancre'
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -134,51 +134,51 @@
|
|||
@media (prefers-reduced-motion: no-preference) {
|
||||
// Adapt the animation duration according to the number of element + 2 (the 2 duplicated)
|
||||
.moving-strip:has(> :nth-child(3)) {
|
||||
animation: marquee 8s linear infinite;
|
||||
animation: marquee 10s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(4)) {
|
||||
animation: marquee 16s linear infinite;
|
||||
animation: marquee 21s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(5)) {
|
||||
animation: marquee 24s linear infinite;
|
||||
animation: marquee 27s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(6)) {
|
||||
animation: marquee 32s linear infinite;
|
||||
animation: marquee 42s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(7)) {
|
||||
animation: marquee 40s linear infinite;
|
||||
animation: marquee 52s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(8)) {
|
||||
animation: marquee 48s linear infinite;
|
||||
animation: marquee 62s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(9)) {
|
||||
animation: marquee 56s linear infinite;
|
||||
animation: marquee 73s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(10)) {
|
||||
animation: marquee 64s linear infinite;
|
||||
animation: marquee 83s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(11)) {
|
||||
animation: marquee 72s linear infinite;
|
||||
animation: marquee 94s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(12)) {
|
||||
animation: marquee 80s linear infinite;
|
||||
animation: marquee 104s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(13)) {
|
||||
animation: marquee 88s linear infinite;
|
||||
animation: marquee 114s linear infinite;
|
||||
}
|
||||
|
||||
.moving-strip:has(> :nth-child(14)) {
|
||||
animation: marquee 96s linear infinite;
|
||||
animation: marquee 125s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,3 +13,7 @@ import "./../modules/sweetalert";
|
|||
// CUSTOM
|
||||
import "./base/common";
|
||||
|
||||
// PAGES
|
||||
import "./pages/strips";
|
||||
|
||||
|
||||
|
|
|
|||
40
resources/ts/bo/pages/strips.ts
Normal file
40
resources/ts/bo/pages/strips.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const stripMedia = document.getElementById("stripItemMedia");
|
||||
if (stripMedia === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaPicto = document.getElementById("mediaSelectorPicto") as HTMLInputElement,
|
||||
mediaImage = document.getElementById("mediaSelectorImage") as HTMLInputElement;
|
||||
|
||||
mediaPicto?.addEventListener("change", function() {
|
||||
hideFormPart(".stripItemPicture");
|
||||
showFormPart(".stripItemPicto");
|
||||
});
|
||||
|
||||
mediaImage?.addEventListener("change", function() {
|
||||
hideFormPart(".stripItemPicto");
|
||||
showFormPart(".stripItemPicture");
|
||||
});
|
||||
});
|
||||
|
||||
function hideFormPart(id: string) {
|
||||
const parts = document.querySelectorAll(id);
|
||||
parts.forEach(partToHide => {
|
||||
partToHide.classList.add("d-none");
|
||||
const inputs = partToHide.querySelectorAll("input");
|
||||
for (const input of inputs) {
|
||||
input.disabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
function showFormPart(id: string) {
|
||||
const parts = document.querySelectorAll(id);
|
||||
parts.forEach(partToShow => {
|
||||
partToShow.classList.remove("d-none");
|
||||
const inputs = partToShow.querySelectorAll("input");
|
||||
for (const input of inputs) {
|
||||
input.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
97
resources/views/bo/pages/strips/form-media-part.blade.php
Normal file
97
resources/views/bo/pages/strips/form-media-part.blade.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<div id="stripItemMedia" class="row">
|
||||
{{-- BUTTONS SELECTOR --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="input-group justify-content-center align-items-center h-100">
|
||||
<input class="btn-check" id="mediaSelectorPicto" name="mediaSelector" type="radio" autocomplete="off"
|
||||
@checked(isset($stripModel->picto))>
|
||||
<label class="btn btn-secondary rounded-start" for="mediaSelectorPicto">{{ __('Pictogramme') }}</label>
|
||||
<input class="btn-check" id="mediaSelectorImage" name="mediaSelector" type="radio" autocomplete="off"
|
||||
@checked(isset($stripModel->picture))>
|
||||
<label class="btn btn-secondary" for="mediaSelectorImage">{{ __('Image') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- PICTO --}}
|
||||
<div @class([
|
||||
"stripItemPicto col-12 col-md-6 mb-3",
|
||||
'd-none' => empty($stripModel->picto),
|
||||
])>
|
||||
@include('bo.partials.inputs.tinyint-enum', [
|
||||
'id' => 'stripPicto',
|
||||
'label' => __('Associer un pictogramme'),
|
||||
'name' => 'picto',
|
||||
'model' => $stripModel ?? null,
|
||||
'required' => false,
|
||||
'associatedModels' => \App\Enums\Strips\PictoEnum::toArray(),
|
||||
'helper' => __('Sélectionnez un pictogramme dans la liste déroulante.'),
|
||||
])
|
||||
</div>
|
||||
{{-- PICTURE --}}
|
||||
<div @class([
|
||||
"stripItemPicture col-12 col-md-6 mb-3",
|
||||
'd-none' => empty($stripModel->picture),
|
||||
])>
|
||||
@include('bo.partials.inputs.varchar-picture', [
|
||||
'id' => "stripItemPicture",
|
||||
'name' => "picture",
|
||||
'width' => 100,
|
||||
'height' => 65,
|
||||
'model' => $stripModel ?? null,
|
||||
'value' => $stripModel->picture ?? null,
|
||||
'helper' => __('crud.minicrud.dimensions_must_be', [
|
||||
'width' => 100,
|
||||
'height' => 65,
|
||||
]),
|
||||
'required' => true,
|
||||
'preview' => false,
|
||||
])
|
||||
</div>
|
||||
{{-- PICTURE_ALT --}}
|
||||
<div @class([
|
||||
"stripItemPicture col-12 col-md-6 mb-3",
|
||||
'd-none' => empty($stripModel->picture),
|
||||
])>
|
||||
@include('bo.partials.inputs.varchar', [
|
||||
'id' => "stripItemPictureAlt",
|
||||
'label' => __(':field de l\':model', [
|
||||
'field' => str(__('validation.custom.alt_attribute'))->ucFirst(),
|
||||
'model' => trans_choice('models.classes.news', 1),
|
||||
]),
|
||||
'hasWordCounter' => true,
|
||||
'name' => "picture_alt",
|
||||
'required' => true,
|
||||
'model' => $stripModel ?? null,
|
||||
'disabled' => empty($stripModel->picture_alt),
|
||||
'value' => $stripModel->picture_alt ?? '',
|
||||
'helper' => __('crud.minicrud.picture_alt_helper'),
|
||||
'placeholder' => __(':field de l\':model', [
|
||||
'field' => str(__('validation.custom.alt_attribute'))->ucFirst(),
|
||||
'model' => trans_choice('models.classes.news', 1),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
{{-- PICTURE_TITLE --}}
|
||||
<div @class([
|
||||
"stripItemPicture col-12 col-md-6 mb-3",
|
||||
'd-none' => empty($stripModel->picture),
|
||||
])>
|
||||
@include('bo.partials.inputs.varchar', [
|
||||
'id' => "stripItemPictureTitle",
|
||||
'label' => __(':field de l\':model', [
|
||||
'field' => str(__('validation.custom.title_attribute'))->ucFirst(),
|
||||
'model' => trans_choice('models.classes.news', 1),
|
||||
]),
|
||||
'hasWordCounter' => true,
|
||||
'name' => "picture_title",
|
||||
'required' => true,
|
||||
'model' => $stripModel ?? null,
|
||||
'disabled' => empty($stripModel->picture_title),
|
||||
'value' => $stripModel->picture_title ?? '',
|
||||
'helper' => __('crud.minicrud.picture_title_helper'),
|
||||
'placeholder' => __(':field de l\':model', [
|
||||
'field' => str(__('validation.custom.title_attribute'))->ucFirst(),
|
||||
'model' => trans_choice('models.classes.news', 1),
|
||||
]),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,25 +1,17 @@
|
|||
<div class="row">
|
||||
{{-- PICTO --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
{{-- MEDIA --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border p-3">
|
||||
<legend>{{ Str::ucfirst(__('validation.custom.picto')) }}</legend>
|
||||
<legend>{{ str(__('validation.custom.media'))->ucFirst()->plural() }} *</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@include('bo.partials.inputs.tinyint-enum', [
|
||||
'id' => 'stripPicto',
|
||||
'label' => __('Associer un pictogramme'),
|
||||
'name' => 'picto',
|
||||
'model' => $stripModel ?? null,
|
||||
'required' => true,
|
||||
'associatedModels' => \App\Enums\Strips\PictoEnum::toArray(),
|
||||
'helper' => __('Sélectionnez un pictogramme dans la liste déroulante.'),
|
||||
])
|
||||
@include('bo.pages.strips.form-media-part')
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- NEWS_ID --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="h-100 border p-3">
|
||||
<legend>{{ Str::ucfirst(trans_choice('models.classes.news', 1)) }}</legend>
|
||||
<div class="row">
|
||||
|
|
|
|||
|
|
@ -3,21 +3,25 @@
|
|||
<thead>
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => [
|
||||
'picto' => Str::ucfirst(__('validation.custom.picto')),
|
||||
'media' => Str::ucfirst(__('validation.custom.media')),
|
||||
'text' => Str::ucfirst(__('validation.attributes.content')),
|
||||
'news_id' => Str::ucfirst(trans_choice('models.classes.news', 1)),
|
||||
'published' => Str::ucfirst(__('validation.custom.activated')),
|
||||
'updated_at' => Str::ucfirst(__('validation.attributes.updated_at')),
|
||||
],
|
||||
'ignore' => ['media'],
|
||||
])
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($stripModels as $stripModel)
|
||||
<tr class="border-bottom list-item">
|
||||
<tr class="border-bottom">
|
||||
<td class="text-center align-middle">
|
||||
@if ($stripModel->picto !== \App\Enums\Strips\PictoEnum::none)
|
||||
<img src="{{ Vite::asset($stripModel->picto->picture()) }}" title="{{ $stripModel->picto->title() }}"
|
||||
alt="{{ $stripModel->picto->alt() }}" height="50">
|
||||
@if ($stripModel->picto && $stripModel->picto !== \App\Enums\Strips\PictoEnum::none)
|
||||
<img src="{{ Vite::asset($stripModel->picto->picture()) }}" title="{{ $stripModel->picto->title() }}"
|
||||
alt="{{ $stripModel->picto->alt() }}" height="50">
|
||||
@elseif ($stripModel->picture)
|
||||
<img src="{{ asset($stripModel->picture) }}" title="{{ $stripModel->picture_title }}"
|
||||
alt="{{ $stripModel->picture_alt }}" height="50">
|
||||
@else
|
||||
{{ __('Aucun') }}
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
<div class="strip-item d-flex align-items-center px-3 py-2 text-white">
|
||||
<div class="strip-item-picto d-flex justify-content-center align-items-center me-4 overflow-hidden">
|
||||
<img class="object-fit-contain w-100" src="{{ Vite::asset($stripModel->picto->picture()) }}" title="{{ $stripModel->picto->title() }}"
|
||||
alt="{{ $stripModel->picto->alt() }}">
|
||||
@if ($stripModel->picto)
|
||||
<img class="object-fit-contain w-100" src="{{ Vite::asset($stripModel->picto->picture()) }}" title="{{ $stripModel->picto->title() }}"
|
||||
alt="{{ $stripModel->picto->alt() }}">
|
||||
@else
|
||||
<img class="object-fit-contain w-100" src="{{ asset($stripModel->picture) }}" title="{{ $stripModel->picture_title }}"
|
||||
alt="{{ $stripModel->picture_alt }}">
|
||||
@endif
|
||||
</div>
|
||||
<div class="strip-item-content">
|
||||
<p>{!! clean($stripModel->text) !!}</p>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue