Fix minicrud usage + add Video on concepts bloc

This commit is contained in:
Jérémy Munsch 2023-05-10 18:46:44 +02:00
parent 05ec9be065
commit ee09078cc2
No known key found for this signature in database
GPG key ID: 18361AF3BFEC0FEC
17 changed files with 408 additions and 239 deletions

View file

@ -22,4 +22,5 @@ enum InputType: int
case text = 12;
case url = 13;
case videoVimeo = 14;
case videoYoutube = 15;
}

View file

@ -60,6 +60,7 @@ class SecureHeaders
]) . ';',
"img-src * data: blob:;",
'frame-src ' . implode(' ', [
'https://www.youtube.com',
'https://www.google.com/recaptcha/',
'https://recaptcha.google.com/recaptcha/',
'https://www.google.com/maps/'

View file

@ -11,6 +11,13 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
{
use HasPicture;
/**
* The model parameter name
*
* @var string
*/
protected $modelName = 'concept';
/**
* Determine if the user is authorized to make this request.
*
@ -57,6 +64,7 @@ class StoreConceptRequest extends UpdateMiniCrudRequest
'picture_title' => 'required|min:3|max:255',
];
return \array_merge(
parent::rules(),
$rules,
$this->pictureRules('picture', 1512, 354, 1512, 354, false),
);

View file

@ -11,6 +11,13 @@ class StoreSliderRequest extends UpdateMiniCrudRequest
{
use HasPicture;
/**
* The model parameter name
*
* @var string
*/
protected $modelName = 'slider';
/**
* Determine if the user is authorized to make this request.
*
@ -60,6 +67,7 @@ class StoreSliderRequest extends UpdateMiniCrudRequest
];
return \array_merge(
$rules,
parent::rules(),
$this->pictureRules('picture', 1270, 930, 1270, 930, false),
);
}

View file

@ -45,6 +45,11 @@ abstract class UpdateMiniCrudRequest extends FormRequest
"data.$iptName.value" => $this->compileValidate('required|numeric', $input)
]);
break;
case InputType::videoYoutube->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('regex:%([^"&?\/\s]{11})%i', $input)
]);
break;
case InputType::string->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('required|string|min:3', $input)
@ -65,37 +70,53 @@ abstract class UpdateMiniCrudRequest extends FormRequest
return $rule;
});
$rules = array_merge($rules, [
"data.$iptName.text" => $mergeRules
"data.$iptName.value" => $mergeRules
]);
break;
case InputType::image->value:
$ipt = $this->data[$iptName];
$max = isset($ipt['dimensionsMax']);
$dim = collect(explode(
$required = $this->isUpdate() ? 'sometimes' : 'required';
$ipt = $this->data[$iptName];
$max = isset($ipt['dimensionsMax']);
$dim = \is_string($input['dimensions']) ? collect(explode(
',',
$ipt['dimensionsMax'] ?? $input['dimensions']
(isset($ipt['dimensionsMax']) and is_string($ipt['dimensionsMax'])) ?
$ipt['dimensionsMax'] : $input['dimensions']
))->mapWithKeys(function ($v) {
$v = explode(' ', $v);
return [$v[0] => $v[1]];
});
}) : $input['dimensions'];
// * Adapt dimensions
$sizes = (object)[
'minHeight' => $dim['height'],
'maxHeight' => $dim['height'],
'minWith' => $dim['width'],
'maxWith' => $dim['width'],
];
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate(
"data.$iptName.value" => [
function (string $attribute, $value, callable $fail) use ($sizes) {
return ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes);
}
],
$this->compileValidate(
implode('|', [
'required',
$required,
'image',
'mimes:png,jpg,jpeg',
sprintf(
'dimensions:%s=%d,%s=%d',
$max ? 'max_height' : 'height',
$dim['hauteur'],
$dim['height'],
$max ? 'max_width' : 'width',
$dim['largeur']
$dim['width']
)
]),
$input
),
"data.$iptName.alt" => $this->compileValidate('required|string|min:5', $input),
"data.$iptName.title" => $this->compileValidate('required|string|min:5', $input)
"data.$iptName.alt" => $this->compileValidate("$required|string|min:5", $input),
"data.$iptName.title" => $this->compileValidate("$required|string|min:5", $input)
]);
break;
case InputType::url->value:
@ -153,4 +174,14 @@ abstract class UpdateMiniCrudRequest extends FormRequest
}
return \implode('|', $out);
}
/**
* Is this request an update request ?
*
* @return boolean
*/
private function isUpdate(): bool
{
return $this->isMethod('PUT');
}
}

View file

@ -5,7 +5,9 @@ namespace App\Lib\Helpers;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
@ -321,4 +323,88 @@ class ToolboxHelper
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
}
/**
* Validate picture
*
* @param string $attribute
* @param string|null $value
* @param callback $fail
* @param object $sizes
* @return void
*/
public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes)
{
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
$fail(trans(':attribute n\'existe pas dans le système de fichier', [
'attribute' => $attribute
]));
return;
}
/** @var string */
$fileFullPath = self::getUploadedFileFullPath($value, $useStorage);
if (
!\in_array(self::getUploadedFileMimeType($value, $useStorage), [
'image/jpeg', 'image/jpg', 'image/png', 'image/gif'
])
) {
$fail(trans(':attribute doit être une image de type \'image/jpeg,image/jpg,image/png,image/gif\'', [
'attribute' => $attribute
]));
}
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
$fail(trans(':attribute impossible de valider les dimensions', [
'attribute' => $attribute
]));
} else {
$width = intval($dimensions[0]);
$height = intval($dimensions[1]);
$xMessage = trans(
":attribute la largeur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minWith === $sizes->maxWith) {
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWith}px");
}
$yMessage = trans(
":attribute la hauteur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minHeight === $sizes->maxHeight) {
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minWith}px");
}
if (($width < $sizes->minWith) or ($width > $sizes->maxWith)) {
$fail($xMessage);
}
if (($height < $sizes->minHeight) or ($height > $sizes->maxHeight)) {
$fail($yMessage);
}
} //end if
}
/**
* Get the file full path
*
* @param string $value
* @param boolean $useStorage
* @return string
*/
private static function getUploadedFileFullPath(string $value, bool $useStorage): string
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = Storage::disk();
return !$useStorage ? (realpath($value) ?: $value) : $disk->path($value);
}
/**
* Get the file mimetype
*
* @param string $value
* @param boolean $useStorage
* @return string|false
*/
private static function getUploadedFileMimeType(string $value, bool $useStorage)
{
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
}
}

View file

@ -199,115 +199,50 @@ class Concept extends Model
string $imgTitle = ''
) {
$color = $color ?: \collect(ColorsEnum::cases())->random()->value;
return [
// * BLOC 1
"bloc_1_title" => [
"label" => "Bloc 1 - Title",
"inputType" => InputType::string->value,
"value" => $title,
"validate" => "required|min:4|max:100"
],
"bloc_1_color" => [
"label" => "Bloc 1 - Color",
"inputType" => InputType::selectEnum->value,
"value" => $color,
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
],
"bloc_1_text" => [
"label" => "Bloc 1 - Text",
"inputType" => InputType::text->value,
"value" => $text,
"validate" => "string|min:10"
],
"bloc_1_image" => [
"label" => "Bloc 1 - Image",
"dimensions" => ["width" => 1140, "height" => 795],
"inputType" => InputType::image->value,
"alt" => $imgAlt,
"title" => $imgTitle,
"value" => $img,
],
// * BLOC 2
"bloc_2_title" => [
"label" => "Bloc 2 - Title",
"inputType" => InputType::string->value,
"value" => $title,
"validate" => "required|min:4|max:100"
],
"bloc_2_color" => [
"label" => "Bloc 2 - Color",
"inputType" => InputType::selectEnum->value,
"value" => $color,
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
],
"bloc_2_text" => [
"label" => "Bloc 2 - Text",
"inputType" => InputType::text->value,
"value" => $text,
"validate" => "string|min:10"
],
"bloc_2_image" => [
"label" => "Bloc 2 - Image",
"dimensions" => ["width" => 1140, "height" => 795],
"inputType" => InputType::image->value,
"alt" => $imgAlt,
"title" => $imgTitle,
"value" => $img,
],
// * BLOC 3
"bloc_3_title" => [
"label" => "Bloc 3 - Title",
"inputType" => InputType::string->value,
"value" => $title,
"validate" => "required|min:4|max:100"
],
"bloc_3_color" => [
"label" => "Bloc 3 - Color",
"inputType" => InputType::selectEnum->value,
"value" => $color,
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
],
"bloc_3_text" => [
"label" => "Bloc 3 - Text",
"inputType" => InputType::text->value,
"value" => $text,
"validate" => "string|min:10"
],
"bloc_3_image" => [
"label" => "Bloc 3 - Image",
"dimensions" => ["width" => 1140, "height" => 795],
"inputType" => InputType::image->value,
"alt" => $imgAlt,
"title" => $imgTitle,
"value" => $img,
],
// * BLOC 4
"bloc_4_title" => [
"label" => "Bloc 4 - Title",
"inputType" => InputType::string->value,
"value" => $title,
"validate" => "required|min:4|max:100"
],
"bloc_4_color" => [
"label" => "Bloc 4 - Color",
"inputType" => InputType::selectEnum->value,
"value" => $color,
"validate" => ["required", "integer", new Enum(ColorsEnum::class)]
],
"bloc_4_text" => [
"label" => "Bloc 4 - Text",
"inputType" => InputType::text->value,
"value" => $text,
"validate" => "string|min:10"
],
"bloc_4_image" => [
"label" => "Bloc 4 - Image",
"dimensions" => ["width" => 1140, "height" => 795],
"inputType" => InputType::image->value,
"alt" => $imgAlt,
"title" => $imgTitle,
"value" => $img,
],
];
$data = [];
for ($i = 1; $i <= 4; $i++) {
$data["bloc_{$i}_title"] = [
'label' => "Bloc {$i} - Title",
'inputType' => InputType::string->value,
'value' => $title,
'validate' => 'required|min:4|max:100'
];
$data["bloc_{$i}_color"] = [
'label' => "Bloc {$i} - Color",
'inputType' => InputType::selectEnum->value,
'value' => $color,
'validate' => ['required', 'integer', new Enum(ColorsEnum::class)]
];
$data["bloc_{$i}_text"] = [
'label' => "Bloc {$i} - Text",
'inputType' => InputType::text->value,
'value' => $text,
'validate' => 'string|min:10'
];
$data["bloc_{$i}_image"] = [
'label' => "Bloc {$i} - Image",
'dimensions' => ['width' => 1140, 'height' => 795],
'inputType' => InputType::image->value,
'alt' => $imgAlt,
'title' => $imgTitle,
'value' => $img,
'validate' => "required_if:data.bloc_{$i}_has_video.value,false",
];
$data["bloc_{$i}_video_youtube"] = [
'label' => "Bloc {$i} - Video",
'inputType' => InputType::videoYoutube->value,
'value' => '',
'validate' => "required_if:data.bloc_{$i}_has_video.value,true|nullable|regex:%([^\"&?\/\s]{11})%i",
'required' => false
];
$data["bloc_{$i}_has_video"] = [
'label' => "Bloc {$i} - Display video",
'inputType' => InputType::boolean->value,
'value' => false,
];
} //end for
return $data;
}
}

View file

@ -151,18 +151,19 @@ trait MiniCrudModel
$data[$o]['value'] = \preg_replace(
'/^\/|^/',
'',
FileStorageHelper::storeFile($this, $input['value'])
FileStorageHelper::storeFile($this, $input['value'], true)
);
break;
case InputType::selectEnum->value:
case InputType::boolean->value:
case InputType::text->value:
case InputType::password->value:
case InputType::email->value:
case InputType::number->value:
case InputType::string->value:
case InputType::videoVimeo->value:
case InputType::videoYoutube->value:
break;
case InputType::string->value:
case InputType::text->value:
case InputType::url->value:
ToolboxHelper::assertNoInternalBoUrls('content', $input['value']);
break;

View file

@ -2,8 +2,7 @@
namespace App\Traits\Requests;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use App\Lib\Helpers\ToolboxHelper;
/**
* ! This assumes file system is using local storage
@ -67,7 +66,7 @@ trait HasPicture
$name => [
!$nullable ? 'required' : 'nullable',
function (string $attribute, $value, callable $fail) use ($sizes) {
return $this->validatePicture($attribute, $value, $fail, $sizes);
return ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes);
}
]
];
@ -108,59 +107,6 @@ trait HasPicture
];
}
/**
* Validate picture
*
* @param string $attribute
* @param string|null $value
* @param callback $fail
* @param object $sizes
* @return void
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
*/
private function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes)
{
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
$fail(trans(":attribute n'existe pas dans le système de fichier"));
return;
}
/** @var string */
$fileFullPath = $this->getUploadedFileFullPath($value, $useStorage);
if (
!\in_array($this->getUploadedFileMimeType($value, $useStorage), [
'image/jpeg', 'image/jpg', 'image/png', 'image/gif'
])
) {
$fail(trans(":attribute doit être une image de type 'image/jpeg,image/jpg,image/png,image/gif'"));
}
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
$fail(trans(":attribute impossible de valider les dimensions"));
} else {
$width = intval($dimensions[0]);
$height = intval($dimensions[1]);
$xMessage = trans(
":attribute la largeur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minWith === $sizes->maxWith) {
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWith}px");
}
$yMessage = trans(
":attribute la hauteur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minHeight === $sizes->maxHeight) {
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minWith}px");
}
if (($width < $sizes->minWith) or ($width > $sizes->maxWith)) {
$fail($xMessage);
}
if (($height < $sizes->minHeight) or ($height > $sizes->maxHeight)) {
$fail($yMessage);
}
} //end if
}
/**
* Merges products pictures fields with request data
*
@ -225,30 +171,4 @@ trait HasPicture
}
} //end if
}
/**
* Get the file full path
*
* @param string $value
* @param boolean $useStorage
* @return string
*/
private function getUploadedFileFullPath(string $value, bool $useStorage): string
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = Storage::disk();
return !$useStorage ? (realpath($value) ?: $value) : $disk->path($value);
}
/**
* Get the file mimetype
*
* @param string $value
* @param boolean $useStorage
* @return string|false
*/
private function getUploadedFileMimeType(string $value, bool $useStorage)
{
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
}
}

7
package-lock.json generated
View file

@ -32,6 +32,7 @@
"eslint": "^8.35.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-vue": "^9.4.0",
"fslightbox": "^3.4.1",
"laravel-vite-plugin": "^0.7.2",
"postcss": "^8.4.23",
"postcss-discard-comments": "^5.1.2",
@ -5178,6 +5179,12 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/fslightbox": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.4.1.tgz",
"integrity": "sha512-/YkPP9jCnZMIlPuJPUo10JTCOCntU0vHeIKe0cB5ruR0ss2QCLhzxY5h24grZ2gUsF//0NXik7iGMU05RV/jcg==",
"dev": true
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",

View file

@ -39,6 +39,7 @@
"eslint": "^8.35.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-vue": "^9.4.0",
"fslightbox": "^3.4.1",
"laravel-vite-plugin": "^0.7.2",
"postcss": "^8.4.23",
"postcss-discard-comments": "^5.1.2",

View file

@ -1 +1,8 @@
// Empty.
.youtube-play-button {
top: 50%;
left: 50%;
font-size: 3rem;
transform: translateX(-50%) translateY(-50%);
}

View file

@ -1,6 +1,8 @@
// ASSETS
import.meta.glob(["./../assets/images/**", "./../assets/fonts/**"]);
import "fslightbox";
// UTILITIES
import "./utilities/bootstrap";
import "./utilities/fontawesome";

View file

@ -39,7 +39,7 @@ import {
faHeader,
faCircleCheck,
} from "@fortawesome/free-solid-svg-icons";
import { faCircleXmark } from "@fortawesome/free-regular-svg-icons";
import { faCircleXmark, faCirclePlay } from "@fortawesome/free-regular-svg-icons";
config.autoReplaceSvg = false;
library.add(faEraser);
@ -83,5 +83,6 @@ library.add(faCircleXmark);
library.add(faCircleNotch);
library.add(faSliders);
library.add(faCircleCheck);
library.add(faCirclePlay);
dom.watch();

View file

@ -1,15 +1,37 @@
{{-- MINI CRUD EDIT WHEN JSON IS TRANSLATABLE --}}
@php
$data = (isset($model->data)) ? $model->getEmptyData() : $conceptData;
if (isset($model->data)) {
($model->data = $model->getTranslation('data', App::currentLocale()));
}
@endphp
@foreach ($data as $k => $input)
@php
$input = json_decode(json_encode($input), true);
@endphp
@switch(intval($input['inputType']))
@case(intval(App\Enums\InputType::videoYoutube->value))
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ $input['label'] }} *</legend>
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => Str::slug($input['label']),
'label' => $input['label'],
'hasWordCounter' => true,
'name' => 'data['.$k.'][value]',
'value' => old("data.{$k}.value", $model->data[$k]['value'] ?? null),
'required' => isset($input['required']) ? !empty($input['required']) : true,
'model' => $model ?? null,
'helper' => __('video id eg: keZURbOo4-M')
])
@include('modules.input-error', [
'inputName' => "data.{$k}.value"
])
</div>
</div>
</fieldset>
</div>
@break
@case(intval(App\Enums\InputType::url->value))
@case(intval(App\Enums\InputType::string->value))
<div class="col-12 col-md-6 mb-3">
@ -18,32 +40,60 @@ if (isset($model->data)) {
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => Str::slug($input["label"]),
'label' => $input['label'] . ' of the ' . __('models.classes.concepts'),
'id' => Str::slug($input['label']),
'label' => $input['label'],
'hasWordCounter' => true,
'name' => 'data['.$k.'][value]',
'value' => old("data.{$k}.value", $model->data[$k]["value"] ?? null),
'required' => true,
'value' => old("data.{$k}.value", $model->data[$k]['value'] ?? null),
'required' => isset($input['required']) ? !empty($input['required']) : true,
'model' => $model ?? null,
'helper' => __('validation.between.string', [
'attribute' => $input['label'] . ' of the ' . __('models.classes.concepts'),
'attribute' => $input['label'],
'min' => 3,
'max' => 255
])
])
@include('modules.input-error', [
'inputName' => "data.{$k}.value"
])
</div>
</div>
</fieldset>
</div>
@break
@break
@case(intval(App\Enums\InputType::number->value))
<div class="form-group">
<label for="{{ $k }}"><small>{{ $input['label'] }}*</small></label>
<input id="{{ $k }}" type="number" step="0.01" class="form-control"
name="data[{{ $k }}][value]" placeholder="{{ $input['label'] }}"
value="{{ old("data.{$k}.value", ($input['value'] ?? '')) }}" required>
<div class="row">
<div class="col">
<fieldset class="border p-3 mb-3">
<div class="d-flex flex-row justify-content-start align-items-center mb-2">
<legend class="w-auto m-0">
<label for="number{{$k}}" class="col-form-label">
<b>{{ $input['label'] }}</b>
</label>
</legend>
@if(!empty($input['tooltip']))
<span class="ms-1" data-bs-toggle="tooltip" data-bs-html="true" title="{{ $input['tooltip'] }}">
<i class="fa fa-question-circle"></i>
</span>
@endif
</div>
<div class="row mb-3">
<div class="form-group">
<input id="number{{$k}}" type="number" step="0.01" class="form-control"
aria-describedby="NumberHelp{{$k}}"
name="data[{{ $k }}][value]" placeholder="{{ $input['label'] }}"
value="{{ old("data.{$k}.value") ?? ($input['value'] ?? '') }}" @if(!isset($input['required']) or $input['required']) required @endif>
@include('back::modules.input-error', [
'inputName' => "data.{$k}.value",
'helperId' => "NumberHelp{$k}",
'helper' => $input['helper'] ?? '',
])
</div>
</div>
</fieldset>
</div>
</div>
@break
@case(intval(App\Enums\InputType::text->value))
@ -53,23 +103,49 @@ if (isset($model->data)) {
<div class="row mb-3">
<div class="col-12">
@include('bo.partials.inputs.text-html', [
'id' => Str::slug($input["label"]),
'name' => 'data['.$k.'][value]',
'value' =>old("data.{$k}.value", $model->data[$k]["value"] ?? null),
'id' => Str::slug($input['label']),
'name' => "data[{$k}][value]",
'value' =>old("data.{$k}.value", $model->data[$k]['value'] ?? null),
'model' => $model ?? null,
'helper' => __('crud.minicrud.text_warning') . '. ' . __('validation.min.string', [
'attribute' => $input['label'],
'min' => 3
]),
])
@include('modules.input-error', [
'inputName' => "data.{$k}.value"
])
</div>
</div>
</fieldset>
</div>
@include('modules.input-error', ['inputName' => 'data['.$k.'][value]'])
@break
@case(intval(App\Enums\InputType::boolean->value))
<div class="col-12 col-md-6 mb-3">
<fieldset class="border bg-white p-3">
<legend>{{ $input['label'] }} *</legend>
<div class="row mb-3">
<div class="col-12">
<label class="col-form-label" for="{{ Str::slug($input['label']) }}"><b>{{ __('crud.minicrud.visibility_label') }}</b></label>
<div class="form-check form-switch ms-2">
<input
id="{{ Str::slug($input['label']) }}"
aria-describedby="{{ Str::slug($input['label']) }}Help"
name="data[{{ $k }}][value]"
type="checkbox"
class="ml-2 form-check-input"
value="1"
@if(old("data.{$k}.value", (old('_token') ? false : ($model->data[$k]['value'] ?? null ?? false)))) checked @endif>
</div>
@include('modules.input-error', [
'inputName' => "data.{$k}.value", 'helperId' => Str::slug($input['label']). 'Help' , 'helper' => __('crud.minicrud.visibility_helper')
])
</div>
</div>
</fieldset>
</div>
@break
@case(intval(App\Enums\InputType::image->value))
<div class="col-12 mb-3">
<fieldset class="border h-100 bg-white p-3">
@ -78,11 +154,11 @@ if (isset($model->data)) {
{{-- PICTURE_ALT --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => Str::slug($input["label"]) . '-alt',
'id' => Str::slug($input['label']) . '-alt',
'label' => __('crud.minicrud.picture_alt_label'),
'hasWordCounter' => true,
'name' => 'data['.$k.'][alt]',
'value' => old("data.{$k}.alt", $model->data[$k]["alt"] ?? null),
'value' => old("data.{$k}.alt", $model->data[$k]['alt'] ?? null),
'required' => true,
'model' => $model ?? null,
'helper' => __('crud.minicrud.picture_alt_helper') . '. ' . __('validation.min.string', [
@ -90,15 +166,18 @@ if (isset($model->data)) {
'min' => 3
]),
])
@include('modules.input-error', [
'inputName' => "data.{$k}.alt"
])
</div>
{{-- PICTURE_TITLE --}}
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => Str::slug($input["label"]) . '-title',
'id' => Str::slug($input['label']) . '-title',
'label' => __('crud.minicrud.picture_title_label'),
'hasWordCounter' => true,
'name' => 'data['.$k.'][title]',
'value' => old("data.{$k}.title", $model->data[$k]["title"] ?? null),
'value' => old("data.{$k}.title", $model->data[$k]['title'] ?? null),
'required' => true,
'model' => $model ?? null,
'helper' => __('crud.minicrud.picture_title_helper') . '. ' . __('validation.min.string', [
@ -106,16 +185,19 @@ if (isset($model->data)) {
'min' => 3
]),
])
@include('modules.input-error', [
'inputName' => "data.{$k}.title"
])
</div>
{{-- PICTURE --}}
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar-picture', [
'id' => Str::slug($input["label"]),
'name' => 'data['.$k.'][value]',
'id' => Str::slug($input['label']),
'name' => "data[{$k}][value]",
'width' => $input['dimensions']['width'],
'height' => $input['dimensions']['height'],
'model' => $model ?? null,
'value' => old("data.{$k}.value", $model->data[$k]["value"] ?? null),
'value' => old("data.{$k}.value", $model->data[$k]['value'] ?? null),
'helper' => __('crud.minicrud.dimensions_must_be', [
'width' => $input['dimensions']['width'],
'height' => $input['dimensions']['height'],
@ -123,11 +205,45 @@ if (isset($model->data)) {
'required' => true,
'preview' => true,
])
@include('modules.input-error', [
'inputName' => "data.{$k}.value"
])
</div>
</div>
</fieldset>
</div>
@break
@case(App\Enums\InputType::email->value)
<div class="row">
<div class="col">
<fieldset class="border p-3 mb-3">
<div class="d-flex flex-row justify-content-start align-items-center mb-2">
<legend class="w-auto m-0">
<label for="title{{$k}}" class="col-form-label">
<b>{{ $input['label'] }}</b>
</label>
</legend>
@if(!empty($input['tooltip']))
<span class="ms-1" data-bs-toggle="tooltip" data-bs-html="true" title="{{ $input['tooltip'] }}">
<i class="fa fa-question-circle"></i>
</span>
@endif
</div>
<div class="row mb-3">
<div class="form-group">
<input id="title{{$k}}" type="email" class="form-control" name="data[{{$k}}][value]"
placeholder="{{ $input['label'] }}" value="{{ old("data.{$k}.value") ?? ($input['value'] ?? '') }}" @if(!isset($input['required']) or $input['required']) required @endif>
@include('modules.input-error', [
'inputName' => "data.{$k}.value",
'helperId' => "{$k}StringHelp",
'helper' => $input['helper'] ?? '',
])
</div>
</div>
</fieldset>
</div>
</div>
@break
@case(intval(App\Enums\InputType::imageArray->value))
@case(intval(App\Enums\InputType::labelArray->value))
@case(intval(App\Enums\InputType::selectEnum->value))
@ -139,13 +255,16 @@ if (isset($model->data)) {
@include('bo.partials.inputs.tinyint-enum', [
'id' => Str::slug($input["label"]),
'label' => __('crud.minicrud.associated_enum', ['enum' => $input['label']]),
'name' => 'data['.$k.'][value]',
'name' => "data[{$k}][value]",
'model' => $model ?? null,
'value' => old("data.{$k}.value", $model->data[$k]["value"] ?? null),
'value' => old("data.{$k}.value", $model->data[$k]['value'] ?? null),
'required' => true,
'associatedModels' => $selectedEnum ?? [],
'helper' => __('crud.minicrud.enum_select', ['enum' => $input['label']]),
])
@include('modules.input-error', [
'inputName' => "data.{$k}.value"
])
</div>
</div>
</fieldset>
@ -156,3 +275,21 @@ if (isset($model->data)) {
@php throw new Exception('Input type not handled'); @endphp
@endswitch
@endforeach
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function() {
let minicrud = document.getElementById('minicrud').closest('form');
if (minicrud) {
minicrud.addEventListener('submit', function(e) {
document.querySelectorAll('input[type="file"]').forEach(function(input) {
if (input.dataset['old-value'] && !input.value) {
input.setAttribute('type', 'text');
input.value = input.getAttribute('old-value');
}
});
});
}
});
</script>
@endpush

View file

@ -143,15 +143,15 @@
</div>
{{-- MINICRUD --}}
<div class="col-12 mb-3">
<button class="btn btn-primary col-form-label rounded-0 dropdown-toggle w-100" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
<button class="btn btn-primary col-form-label rounded-0 dropdown-toggle w-100" type="button" data-bs-toggle="collapse" data-bs-target="#minicrud" aria-expanded="false" aria-controls="minicrud">
<b>{{ __('ALL BLOCS') }}</b>
</button>
<div class="collapse" id="collapseExample">
<div class="collapse" id="minicrud">
<div class="card card-body bg-light rounded-0">
<div class="row">
@include('bo.modules.minicrud-form-inputs', [
'model' => $conceptModel ?? $conceptData,
'selectedEnum' => \App\Enums\Concepts\ColorsEnum::toArray()
'model' => $conceptModel ?? $conceptData,
'selectedEnum' => \App\Enums\Concepts\ColorsEnum::toArray()
])
</div>
</div>

View file

@ -3,9 +3,32 @@ $color = \App\Enums\Concepts\ColorsEnum::make($conceptModel->data["bloc_{$number
@endphp
<div class="flex flex-wrap flex-row my-3 sm:my-0 sm:even:flex-row sm:odd:flex-row-reverse">
@if(!empty($conceptModel->data["bloc_{$number}_has_video"]['value']))
<div class="basis-full sm:basis-1/2 flex">
<a
class="relative w-full"
data-fslightbox="https://www.youtube.com/watch?v={{ $conceptModel->data["bloc_{$number}_video_youtube"]['value'] }}"
href="https://www.youtube.com/watch?v={{ $conceptModel->data["bloc_{$number}_video_youtube"]['value'] }}"
target="_blank"
class="position-absolute top-50 start-50 translate-middle"
data-fancybox>
<img
class="w-full"
@if(!empty($conceptModel->data["bloc_{$number}_image"]['value']))
src="{{ asset($conceptModel->data["bloc_{$number}_image"]['value']) }}"
@else
src="{{ 'https://i.ytimg.com/vi/' . $conceptModel->data["bloc_{$number}_video_youtube"]['value'] . '/hqdefault.jpg' }}"
@endif
alt="{{ $conceptModel->data["bloc_{$number}_image"]['alt'] }}"
title="{{ $conceptModel->data["bloc_{$number}_image"]['title'] }}">
<i class="youtube-play-button absolute top-50 left-50 fa-regular fa-circle-play"></i>
</a>
</div>
@else
<div class="basis-full sm:basis-1/2 flex">
<img src="{{ asset($conceptModel->data["bloc_{$number}_image"]['value']) }}" alt="{{ $conceptModel->data["bloc_{$number}_image"]['alt'] }}" title="{{ $conceptModel->data["bloc_{$number}_image"]['title'] }}">
</div>
@endif
<div class="basis-full sm:basis-1/2 order-2 text-weiss flex items-center" style="background-color: {{ \App\Enums\Concepts\ColorsEnum::make($color)->color() }}">
<div class="p-6 sm:pl-6 sm:py-4 lg:pl-16 lg:py-8 xl:pl-32 xl:py-12 max-w-xl">
<h3 class="text-h2-sm md:text-h2-md lg:text-h2-lg xl:text-h2 mb-2 lg:mb-4 font-scarletwood">{{ $conceptModel->data["bloc_{$number}_title"]['value'] }}</h3>