Merge branch 'issue-77-card-height' into issue-77

This commit is contained in:
Nicolas Demangeat 2024-09-24 09:47:53 +02:00
commit 7a1c4d3dbe
81 changed files with 1439 additions and 683 deletions

View file

@ -3,7 +3,6 @@ APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
ASSET_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
@ -38,26 +37,6 @@ MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Sentry
SENTRY_LARAVEL_DSN=
@ -82,3 +61,10 @@ LDC_WEB_CIDR_MANUAL_ALLOWED_LIST=""
MESBR_REF_SITE=
MESBR_REF_CAMP=
MESBR_ENDPOINT=
# SAML
SAML2_DEFAULT_TENANT_UUID=
SAML2_SP_CERT_x509=
SAML2_SP_CERT_PRIVATEKEY=
SAML2_CONTACT_TECHNICAL_EMAIL=
SAML2_CONTACT_SUPPORT_EMAIL=

View file

@ -24,13 +24,11 @@ class FetchDigitalRecruiterOffersCommand extends Command
/**
* Execute the console command.
*
* @return integer
* @return void
*/
public function handle()
public function handle(): void
{
(new FetchDigitalRecruiterOffers())->handle();
$this->info('Offers fetch 👌');
return 0;
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Console\Commands;
use App\Jobs\FetchMesBr;
use Illuminate\Console\Command;
class FetchMesBrCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:mesbr';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fetch mesbr discounts';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
(new FetchMesBr())->handle();
$this->info('Discounts fetch 👌');
}
}

View file

@ -26,10 +26,11 @@ class TestMail extends Command
*
* @return void
*/
public function handle()
public function handle(): void
{
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
});
$this->info('Mail send 👌');
}
}

View file

@ -47,13 +47,6 @@ class UserCreate extends Command
*/
protected $email;
/**
* The password of the new user.
*
* @var string|null
*/
protected $password;
/**
* The role of the new user.
*
@ -64,9 +57,9 @@ class UserCreate extends Command
/**
* Execute the console command.
*
* @return integer
* @return void
*/
public function handle(): int
public function handle(): void
{
$this->first_name = null;
$this->addFirstName();
@ -77,9 +70,6 @@ class UserCreate extends Command
$this->email = null;
$this->addEmail();
$this->password = null;
$this->addPassword();
$this->role = null;
$this->addRole();
@ -87,7 +77,6 @@ class UserCreate extends Command
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'password' => $this->password,
'role' => $this->role,
'published' => true,
'published_at' => Carbon::now(),
@ -95,8 +84,6 @@ class UserCreate extends Command
$user->saveOrFail();
$this->info('User created 👌');
return 0;
}
/**
@ -174,22 +161,6 @@ class UserCreate extends Command
}; //end while
}
/**
* Add a password to the user.
*
* @return void
*/
private function addPassword(): void
{
while (
($this->password = $this->secret(
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
)) !== $this->secret('Confirm the password')
) {
continue;
}; //end while
}
/**
* Add a role to the user.
*
@ -199,7 +170,7 @@ class UserCreate extends Command
{
while (is_null($this->role)) {
try {
$tmp = $this->choice(
$tmp = $this->choice(
'Select his role',
[
Str::ucFirst(RoleEnum::conceptor->label()),
@ -207,8 +178,6 @@ class UserCreate extends Command
Str::ucFirst(RoleEnum::visitor->label())
],
Str::ucFirst(RoleEnum::visitor->label()),
$maxAttempts = null,
$allowMultipleSelections = false
);
if ($tmp === Str::ucFirst(RoleEnum::conceptor->label())) {
$tmp = RoleEnum::conceptor;

View file

@ -20,6 +20,6 @@ class HomeController extends Controller
$discountsTotal = $discountModels->sum('value');
return (auth('club')->check())
? view('club.pages.home.homepage', compact('newsClubModels', 'discountModels', 'discountsTotal'))
: view('club.pages.home.guest', compact('newsClubModels'));
: view('club.pages.home.guest', compact('newsClubModels', 'discountsTotal'));
}
}

View file

@ -40,6 +40,12 @@ class Kernel extends HttpKernel
\App\Http\Middleware\SecureHeaders::class
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
'api' => [
'throttle:40,1',
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',

View file

@ -7,7 +7,6 @@ use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rules\Enum;
use Illuminate\Validation\Rules\Password;
class StoreUserRequest extends FormRequest
{
@ -44,14 +43,6 @@ class StoreUserRequest extends FormRequest
'first_name' => 'required|string|min:3|max:255',
'last_name' => 'required|string|min:3|max:255',
'email' => 'required|email:rfc,strict,dns,spoof,filter|unique:users,email',
'password' => [
'required', 'required_with:password_confirmation', 'confirmed', 'max:255', Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised()
],
'role' => ['required', new Enum(RoleEnum::class)],
'published' => 'required|boolean',
];
@ -68,7 +59,6 @@ class StoreUserRequest extends FormRequest
'first_name' => trans('validation.attributes.first_name'),
'last_name' => trans('validation.attributes.last_name'),
'email' => trans('validation.attributes.email'),
'password' => trans('validation.attributes.password'),
'role' => trans('validation.attributes.role'),
'published' => trans('validation.custom.publication')
];

View file

@ -4,7 +4,6 @@ namespace App\Http\Requests\Bo\Users;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;
class UpdateUserRequest extends StoreUserRequest
{
@ -32,11 +31,7 @@ class UpdateUserRequest extends StoreUserRequest
$this->merge([
'published' => $authUserModel->getKey() !== $userModel->getKey() ?
$this->boolean('published') :
true,
'password' => $this->input('password') ??
\optional($this->route('user'))->password,
'password_confirmation' => $this->input('password_confirmation') ??
\optional($this->route('user'))->password
true
]);
}
@ -52,15 +47,7 @@ class UpdateUserRequest extends StoreUserRequest
'required',
'email:rfc,strict,dns,spoof,filter',
Rule::unique('users', 'email')->ignore(\optional($this->route('user'))->getRouteKey())
],
'password' => [
'required', 'required_with:password_confirmation', 'confirmed', 'max:255', Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised()
],
]
]);
}
}

View file

@ -72,7 +72,7 @@ class StaticPage extends Model
});
static::updating(function (self $model) {
self::assertTitleIsUnique($model->seo_title, $model->getKey());
$model->slug = Str::slug($model->seo_title);
$model->slug = Str::slug($model->seo_title ?? $model->title ?? str()->random(20));
if (!is_null($model->picture)) {
$model->picture = FileStorageHelper::storeFile($model, $model->picture, true);
}
@ -123,8 +123,10 @@ class StaticPage extends Model
*/
private static function assertTitleIsUnique(string|null $seo_title, ?int $id = null): void
{
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, 'seo_title', $seo_title, $id);
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($seo_title), $id);
if (!is_null($seo_title)) {
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, 'seo_title', $seo_title, $id);
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($seo_title), $id);
}
}
}

View file

@ -8,14 +8,14 @@ use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
/**
* @property string $first_name Firstname.
* @property string $last_name Lastname.
* @property string $email Email.
* @property string $password Password.
* @property string $remember_token Remember_token.
* @property \App\Enums\Users\RoleEnum $role Role.
* @property \Illuminate\Support\Carbon $last_connection Last_connection.
* @property \Illuminate\Support\Carbon $published Published status.
* @property \Illuminate\Support\Carbon $published_at Publication status update date.
* @property-read \Illuminate\Support\Carbon $created_at Created date.
@ -38,7 +38,6 @@ class User extends Authenticatable
'first_name',
'last_name',
'email',
'password',
'role',
'published',
'published_at',
@ -50,7 +49,6 @@ class User extends Authenticatable
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
@ -61,7 +59,7 @@ class User extends Authenticatable
*/
protected $casts = [
'role' => RoleEnum::class,
'email_verified_at' => 'datetime',
'last_connection' => 'date',
'published' => 'boolean',
'published_at' => 'datetime',
];
@ -74,7 +72,6 @@ class User extends Authenticatable
protected static function booted(): void
{
static::creating(function (self $model) {
self::updatePassword($model);
// * Prevent user elevation privileges
throw_if(
auth('backend')->user() and auth('backend')->user()->role->value() > $model->role->value(),
@ -82,7 +79,6 @@ class User extends Authenticatable
);
});
static::updating(function (self $model) {
self::updatePassword($model);
if (optional(auth('backend')->user())->getKey() === $model->getKey()) {
\validator(
['published' => $model->published],
@ -97,19 +93,4 @@ class User extends Authenticatable
);
});
}
// * METHODS
/**
* Update password.
*
* @param self $model
* @return void
*/
private static function updatePassword(self $model): void
{
if (Hash::needsRehash($model->password)) {
$model->password = Hash::make($model->password);
}
}
}

View file

@ -9,6 +9,13 @@ use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Session;
use Slides\Saml2\Events\SignedIn;
use Slides\Saml2\Events\SignedOut;
class EventServiceProvider extends ServiceProvider
{
@ -38,4 +45,49 @@ class EventServiceProvider extends ServiceProvider
{
return false;
}
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
Event::listen('Slides\Saml2\Events\SignedIn', function (SignedIn $event) {
$messageId = $event->getAuth()->getLastMessageId();
$fromCache = Cache::get(config('cache.prefix') . "_saml_message_id_" . $messageId);
if ($fromCache) {
logger()->error(
'SAML MESSAGE ID HANDLER',
['error' => 'Message ID : ' . $messageId . " replayed !"]
);
abort(403);
} else {
Cache::put(config('cache.prefix') . "_saml_message_id_" . $messageId, $messageId, 28800);
// Cache for 8h.
}
$user = $event->getSaml2User();
$email = $user->getNameId();
$lUser = User::where('email', '=', $email)->first();
if (!$lUser) {
abort(403);
}
Auth::guard('backend')->login($lUser);
session(['sessionIndex' => $user->getSessionIndex()]);
$lUser->last_connection = now();
$lUser->saveQuietly();
});
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
Event::listen('Slides\Saml2\Events\SignedOut', function (SignedOut $event) {
Auth::guard('backend')->logout();
Session::save();
});
}
}

View file

@ -58,7 +58,7 @@ class ViewServiceProvider extends ServiceProvider
Blade::directive('money', function (string $amountVariable) {
// phpcs:ignore Generic.Files.LineLength.TooLong
return "<?php echo e(app('phpMoneyFormatter')->format(new Money({$amountVariable}, app('phpMoneyCurrency')))); ?>";
return "<?php echo e(app('phpMoneyFormatter')->format(new Money({$amountVariable} * 100, app('phpMoneyCurrency')))); ?>";
});
// * Inject menuNodeList

View file

@ -1,6 +1,6 @@
{
"name": "uwil/le-gaulois",
"version": "2.0.0",
"version": "2.1.0",
"type": "project",
"description": "Le Gaulois project.",
"support": {
@ -14,6 +14,7 @@
"require": {
"php": "^8.3",
"ext-bcmath": "*",
"24slides/laravel-saml2": "^2.4",
"axlon/laravel-postal-code-validation": "^3.7",
"carlos-meneses/laravel-mpdf": "^2.1",
"diglactic/laravel-breadcrumbs": "^9.0",

183
composer.lock generated
View file

@ -4,8 +4,83 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "db80cce9d97851f47e3720647bcf6138",
"content-hash": "d9d5353325cde56c23904770ba015a27",
"packages": [
{
"name": "24slides/laravel-saml2",
"version": "2.4.0",
"source": {
"type": "git",
"url": "https://github.com/24Slides/laravel-saml2.git",
"reference": "85dadba29a54f624c29d06b9a2ba0f00186cf665"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/24Slides/laravel-saml2/zipball/85dadba29a54f624c29d06b9a2ba0f00186cf665",
"reference": "85dadba29a54f624c29d06b9a2ba0f00186cf665",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"illuminate/console": "~5.5|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/database": "~5.5|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"illuminate/support": "~5.4|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
"onelogin/php-saml": "^3.0|^4.0",
"php": ">=7.1",
"ramsey/uuid": "^3.8|^4.0"
},
"require-dev": {
"mockery/mockery": "^0.9.9",
"phpunit/phpunit": "^7.5|^9.0",
"squizlabs/php_codesniffer": "^2.3"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Saml2": "Slides\\Saml2\\Facades\\Auth"
},
"providers": [
"Slides\\Saml2\\ServiceProvider"
]
},
"branch-aliases": {
"dev-master": "2.0.8-dev"
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Slides\\Saml2\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Artem Brezhnev",
"email": "brezzhnev@gmail.com"
}
],
"description": "SAML2 Service Provider integration to your Laravel 5.4+ application, based on OneLogin toolkit",
"homepage": "https://github.com/24slides/laravel-saml2",
"keywords": [
"SAML2",
"SSO",
"laravel",
"onelogin",
"saml"
],
"support": {
"issues": "https://github.com/24Slides/laravel-saml2/issues",
"source": "https://github.com/24Slides/laravel-saml2/tree/2.4.0"
},
"time": "2024-04-13T12:57:36+00:00"
},
{
"name": "axlon/laravel-postal-code-validation",
"version": "v3.7.0",
@ -3700,6 +3775,70 @@
],
"time": "2024-09-09T07:06:30+00:00"
},
{
"name": "onelogin/php-saml",
"version": "4.2.0",
"source": {
"type": "git",
"url": "https://github.com/SAML-Toolkits/php-saml.git",
"reference": "d3b5172f137db2f412239432d77253ceaaa1e939"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/SAML-Toolkits/php-saml/zipball/d3b5172f137db2f412239432d77253ceaaa1e939",
"reference": "d3b5172f137db2f412239432d77253ceaaa1e939",
"shasum": ""
},
"require": {
"php": ">=7.3",
"robrichards/xmlseclibs": "^3.1"
},
"require-dev": {
"pdepend/pdepend": "^2.8.0",
"php-coveralls/php-coveralls": "^2.0",
"phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0",
"phpunit/phpunit": "^9.5",
"sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ",
"squizlabs/php_codesniffer": "^3.5.8"
},
"suggest": {
"ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
"ext-dom": "Install xml lib",
"ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
"ext-zlib": "Install zlib"
},
"type": "library",
"autoload": {
"psr-4": {
"OneLogin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHP SAML Toolkit",
"homepage": "https://github.com/SAML-Toolkits/php-saml",
"keywords": [
"Federation",
"SAML2",
"SSO",
"identity",
"saml"
],
"support": {
"email": "sixto.martin.garcia@gmail.com",
"issues": "https://github.com/onelogin/SAML-Toolkits/issues",
"source": "https://github.com/onelogin/SAML-Toolkits/"
},
"funding": [
{
"url": "https://github.com/SAML-Toolkits",
"type": "github"
}
],
"time": "2024-05-30T15:10:40+00:00"
},
{
"name": "paragonie/random_compat",
"version": "v9.99.100",
@ -4845,6 +4984,48 @@
},
"time": "2024-04-13T09:45:55+00:00"
},
{
"name": "robrichards/xmlseclibs",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/robrichards/xmlseclibs.git",
"reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df",
"reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"php": ">= 5.4"
},
"type": "library",
"autoload": {
"psr-4": {
"RobRichards\\XMLSecLibs\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "A PHP library for XML Security",
"homepage": "https://github.com/robrichards/xmlseclibs",
"keywords": [
"security",
"signature",
"xml",
"xmldsig"
],
"support": {
"issues": "https://github.com/robrichards/xmlseclibs/issues",
"source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1"
},
"time": "2020-09-05T13:00:25+00:00"
},
{
"name": "sentry/sentry",
"version": "4.9.0",

View file

@ -56,8 +56,6 @@ return [
'url' => env('APP_URL', 'http://localhost'),
'asset_url' => env('ASSET_URL'),
/*
|--------------------------------------------------------------------------
| Application Timezone

397
config/saml2.php Normal file
View file

@ -0,0 +1,397 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Tenant Model
|--------------------------------------------------------------------------
|
| This will allow you to override the tenant model with your own.
|
*/
'tenantModel' => \Slides\Saml2\Models\Tenant::class,
/*
|--------------------------------------------------------------------------
| Use built-in routes
|--------------------------------------------------------------------------
|
| If "useRoutes" set to true, the package defines five new routes:
|
| Method | URI | Name
| -------|---------------------------------|------------------
| POST | {routesPrefix}/{uuid}/acs | saml.acs
| GET | {routesPrefix}/{uuid}/login | saml.login
| GET | {routesPrefix}/{uuid}/logout | saml.logout
| GET | {routesPrefix}/{uuid}/metadata | saml.metadata
| GET | {routesPrefix}/{uuid}/sls | saml.sls
|
*/
'useRoutes' => true,
/*
|--------------------------------------------------------------------------
| Built-in routes prefix
|--------------------------------------------------------------------------
|
| Here you may define the prefix for built-in routes.
|
*/
'routesPrefix' => '/saml2',
/*
|--------------------------------------------------------------------------
| Middle groups to use for the SAML routes
|--------------------------------------------------------------------------
|
| Note, Laravel 5.2 requires a group which includes StartSession
|
*/
'routesMiddleware' => ['saml'],
/*
|--------------------------------------------------------------------------
| Signature validation
|--------------------------------------------------------------------------
|
| Set to true if you want to use parameters from $_SERVER to validate the signature.
|
*/
'retrieveParametersFromServer' => false,
/*
|--------------------------------------------------------------------------
| Login redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after successful login.
|
*/
'loginRoute' => '/bo',
/*
|--------------------------------------------------------------------------
| Logout redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after successful logout.
|
*/
'logoutRoute' => '/bo',
/*
|--------------------------------------------------------------------------
| Login error redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after login failing.
|
*/
'errorRoute' => '/bo/login-error',
/*
|--------------------------------------------------------------------------
| Strict mode.
|--------------------------------------------------------------------------
|
| If 'strict' is True, then the PHP Toolkit will reject unsigned
| or unencrypted messages if it expects them signed or encrypted
| Also will reject the messages if not strictly follow the SAML
| standard: Destination, NameId, Conditions... are validated too.
|
*/
'strict' => true,
/*
|--------------------------------------------------------------------------
| Debug mode.
|--------------------------------------------------------------------------
|
| When enabled, errors must be printed.
|
*/
'debug' => env('SAML2_DEBUG', env('APP_DEBUG', false)),
/*
|--------------------------------------------------------------------------
| Whether to use `X-Forwarded-*` headers to determine port/domain/protocol.
|--------------------------------------------------------------------------
|
| If 'proxyVars' is True, then the Saml lib will trust proxy headers
| e.g X-Forwarded-Proto / HTTP_X_FORWARDED_PROTO. This is useful if
| your application is running behind a load balancer which terminates SSL.
|
*/
'proxyVars' => true,
/*
|--------------------------------------------------------------------------
| Service Provider configuration.
|--------------------------------------------------------------------------
|
| General setting of the service provider.
|
*/
'sp' => [
/*
|--------------------------------------------------------------------------
| NameID format.
|--------------------------------------------------------------------------
|
| Specifies constraints on the name identifier to be used to
| represent the requested subject.
|
*/
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
/*
|--------------------------------------------------------------------------
| SP Certificates.
|--------------------------------------------------------------------------
|
| Usually x509cert and privateKey of the SP are provided by files placed at
| the certs folder. But we can also provide them with the following parameters.
|
*/
'x509cert' => env('SAML2_SP_CERT_x509', ''),
'privateKey' => env('SAML2_SP_CERT_PRIVATEKEY', ''),
/*
|--------------------------------------------------------------------------
| Identifier (URI) of the SP entity.
|--------------------------------------------------------------------------
|
| Leave blank to use the 'saml.metadata' route.
|
*/
'entityId' => env('SAML2_SP_ENTITYID', ''),
/*
|--------------------------------------------------------------------------
| The Assertion Consumer Service (ACS) URL.
|--------------------------------------------------------------------------
|
| URL Location where the <Response> from the IdP will be returned, using HTTP-POST binding.
| Leave blank to use the 'saml.acs' route.
|
*/
'assertionConsumerService' => [
'url' => '',
],
/*
|--------------------------------------------------------------------------
| The Single Logout Service URL.
|--------------------------------------------------------------------------
|
| Specifies info about where and how the <Logout Response> message MUST be
| returned to the requester, in this case our SP.
|
| URL Location where the <Response> from the IdP will be returned, using HTTP-Redirect binding.
| Leave blank to use the 'saml.sls' route.
|
*/
'singleLogoutService' => [
'url' => ''
],
],
/*
|--------------------------------------------------------------------------
| OneLogin security settings.
|--------------------------------------------------------------------------
|
|
|
*/
'security' => [
'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256',
/*
|--------------------------------------------------------------------------
| NameId encryption
|--------------------------------------------------------------------------
|
| Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
| will be encrypted.
|
*/
'nameIdEncrypted' => true,
/*
|--------------------------------------------------------------------------
| AuthnRequest signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:AuthnRequest> messages sent by
| this SP will be signed. The Metadata of the SP will offer this info
|
*/
'authnRequestsSigned' => true,
/*
|--------------------------------------------------------------------------
| Logout request signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:logoutRequest> messages sent by this SP
| will be signed.
|
*/
'logoutRequestSigned' => true,
/*
|--------------------------------------------------------------------------
| Logout response signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:logoutResponse> messages sent by this SP
| will be signed.
|
*/
'logoutResponseSigned' => true,
/*
|--------------------------------------------------------------------------
| Whether need to sign metadata.
|--------------------------------------------------------------------------
|
| The possible values:
| - false
| - true (use certs)
| - array:
| ```
| [
| 'keyFileName' => 'metadata.key',
| 'certFileName' => 'metadata.crt'
| ]
| ```
|
*/
'signMetadata' => true,
/*
|--------------------------------------------------------------------------
| Requirement to sign messages.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
| <samlp:LogoutResponse> elements received by this SP to be signed.
|
*/
'wantMessagesSigned' => true,
/*
|--------------------------------------------------------------------------
| Requirement to sign assertion elements.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the <saml:Assertion> elements received by
| this SP to be signed.
|
*/
'wantAssertionsSigned' => true,
/*
|--------------------------------------------------------------------------
| Requirement to encrypt NameID.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the NameID received by this SP to be encrypted.
|
*/
'wantNameIdEncrypted' => false,
/*
|--------------------------------------------------------------------------
| Authentication context.
|--------------------------------------------------------------------------
|
| Set to false and no AuthContext will be sent in the AuthNRequest,
|
| Set true or don't present this parameter and you will get an
| AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
| Set an array with the possible auth context values:
| ['urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509']
|
*/
'requestedAuthnContext' => true,
],
/*
|--------------------------------------------------------------------------
| Contact information.
|--------------------------------------------------------------------------
|
| It is recommended to supply a technical and support contacts.
|
*/
'contactPerson' => [
'technical' => [
'givenName' => env('SAML2_CONTACT_TECHNICAL_NAME', env('APP_NAME', 'Technical')),
'emailAddress' => env('SAML2_CONTACT_TECHNICAL_EMAIL', 'no@reply.com')
],
'support' => [
'givenName' => env('SAML2_CONTACT_SUPPORT_NAME', env('APP_NAME', 'Support')),
'emailAddress' => env('SAML2_CONTACT_SUPPORT_EMAIL', 'no@reply.com')
],
],
/*
|--------------------------------------------------------------------------
| Organization information.
|--------------------------------------------------------------------------
|
| The info in en_US lang is recommended, add more if required.
|
*/
'organization' => [
'en-US' => [
'name' => env('SAML2_ORGANIZATION_NAME', env('APP_NAME', 'Name')),
'displayname' => env('SAML2_ORGANIZATION_NAME', env('APP_NAME', 'Name')),
'url' => env('SAML2_ORGANIZATION_URL', env('APP_URL', 'http://url'))
],
],
/**
* Default tenant UUID
*/
'default_tenant_uuid' => env('SAML2_DEFAULT_TENANT_UUID', null)
];

View file

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('email_verified_at');
$table->dropColumn('password');
$table->date('last_connection')->nullable()->after('role');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->timestamp('email_verified_at')->nullable()->after('email');
$table->string('password')->after('email_verified_at');
$table->dropColumn('last_connection');
});
}
};

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::table('customers', function (Blueprint $table) {
$table->string('hashcode')->after('email')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::table('customers', function (Blueprint $table) {
$table->string('email')->after('hashcode')->change();
});
}
};

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.
* @return void
*/
public function up(): void
{
Schema::table('recipes', function (Blueprint $table) {
$table->string('tips', 500)->nullable()->change();
});
}
/**
* Reverse the migrations.
* @return void
*/
public function down(): void
{
Schema::table('recipes', function (Blueprint $table) {
$table->string('tips', 500)->nullable(false)->change();
});
}
};

View file

@ -7,7 +7,7 @@ data:
APP_ENV: "${APP_APP_ENV}"
APP_KEY: "${APP_APP_KEY}"
APP_DEBUG: "${APP_APP_DEBUG}"
APP_URL: "https://${REDIRECT}${APP_DOMAIN}"
APP_URL: "https://${APP_DOMAIN}"
LOG_CHANNEL: "k8s"
DB_HOST: "mariadb.common-services"
DB_DATABASE: "${APP_DB_DATABASE}"
@ -31,6 +31,11 @@ data:
SENTRY_LARAVEL_DSN: "${APP_SENTRY_LARAVEL_DSN}"
DIGITAL_RECRUITER_URL: "${APP_DIGITAL_RECRUITER_URL}"
LDC_WEB_API_KEY: "${APP_LDC_WEB_API_KEY}"
SAML2_SP_CERT_x509: "${APP_SAML2_SP_CERT_x509}"
SAML2_SP_CERT_PRIVATEKEY: "${APP_SAML2_SP_CERT_PRIVATEKEY}"
SAML2_CONTACT_TECHNICAL_EMAIL: "${APP_SAML2_CONTACT_TECHNICAL_EMAIL}"
SAML2_CONTACT_SUPPORT_EMAIL: "${APP_SAML2_CONTACT_SUPPORT_EMAIL}"
SAML2_DEFAULT_TENANT_UUID: "${APP_SAML2_DEFAULT_TENANT_UUID}"
---
apiVersion: v1
@ -40,7 +45,7 @@ metadata:
spec:
storageClassName: "csi-cinder-classic"
accessModes:
- ReadWriteOnce
- ReadWriteOnce
resources:
requests:
storage: $APP_PVC_SIZE
@ -61,25 +66,25 @@ spec:
app: ${CI_PROJECT_PATH_SLUG}-app
spec:
containers:
- name: ${CI_PROJECT_PATH_SLUG}-container
image: $IMAGE_TAG
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
- name: ${CI_PROJECT_PATH_SLUG}-container
image: $IMAGE_TAG
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
imagePullSecrets:
- name: docker-registry-credentials
- name: docker-registry-credentials
securityContext:
runAsUser: 33
runAsGroup: 33
fsGroup: 33
fsGroupChangePolicy: "OnRootMismatch"
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
---
apiVersion: v1
@ -90,8 +95,8 @@ spec:
selector:
app: ${CI_PROJECT_PATH_SLUG}-app
ports:
- port: 80
targetPort: 443
- port: 80
targetPort: 443
---
apiVersion: traefik.io/v1alpha1
@ -100,16 +105,14 @@ metadata:
name: ${CI_PROJECT_PATH_SLUG}-ingress-route
spec:
entryPoints:
- web
- websecure
- web
- websecure
routes:
- match: Host(`${APP_DOMAIN}`) || Host(`www.${APP_DOMAIN}`)
kind: Rule
services:
- name: ${CI_PROJECT_PATH_SLUG}-service
port: 80
middlewares:
- name: redirect-no-www-to-www
- match: Host(`${APP_DOMAIN}`) || Host(`www.${APP_DOMAIN}`)
kind: Rule
services:
- name: ${CI_PROJECT_PATH_SLUG}-service
port: 80
tls:
secretName: ${CRT_TLS_NAME}
@ -127,35 +130,35 @@ spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ${CI_PROJECT_PATH_SLUG}-app
topologyKey: "kubernetes.io/hostname"
namespaces: [$KUBE_NAMESPACE]
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ${CI_PROJECT_PATH_SLUG}-app
topologyKey: "kubernetes.io/hostname"
namespaces: [$KUBE_NAMESPACE]
containers:
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
image: $IMAGE_TAG
imagePullPolicy: IfNotPresent
command:
- "php"
args:
- "artisan"
- "schedule:run"
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
mountPath: /app/srcs/storage
imagePullSecrets:
- name: docker-registry-credentials
volumes:
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
image: $IMAGE_TAG
imagePullPolicy: IfNotPresent
command:
- "php"
args:
- "artisan"
- "schedule:run"
envFrom:
- configMapRef:
name: ${CI_PROJECT_PATH_SLUG}-config-map
volumeMounts:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
mountPath: /app/srcs/storage
imagePullSecrets:
- name: docker-registry-credentials
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
securityContext:
runAsUser: 33
runAsGroup: 33

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View file

@ -41,7 +41,7 @@
position: absolute;
top: -1rem;
right: 0;
max-width: 55%;
max-width: 50%;
height: 110%;
img {
@ -51,6 +51,7 @@
}
@include media-breakpoint-up(xxl) {
right: -3rem;
max-width: 100%;
}

View file

@ -22,32 +22,6 @@
ul {
list-style: none;
}
.breeding-article-image-wrapper {
@include media-breakpoint-up(xl) {
position: absolute;
top: -1rem;
right: 2vw;
max-width: 55%;
height: 110%;
transform: translateX(8vw);
img {
max-width: initial;
min-height: 100%;
}
}
@include media-breakpoint-up(xxl) {
right: 12vw;
max-width: 45%;
}
img {
box-shadow: -4px 8px 14px 0 rgb(0 0 0 / 23%);
transform: rotate(2deg);
}
}
}
}
}

30
resources/sass/fo/pages/commitments.scss Executable file → Normal file
View file

@ -97,7 +97,7 @@
}
.row {
width: 390px;
width: 100%;
@include media-breakpoint-up(md) {
width: 500px;
@ -413,14 +413,36 @@
}
#commitments-banner-text-complex-items {
.banner-title {
color: #000;
@include media-breakpoint-up(md) {
position: absolute;
color: #fff !important;
}
}
.text-custom-placement {
z-index: 1;
transform: translateY(5rem);
@include media-breakpoint-up(md) {
transform: translateY(5rem);
}
}
~#commitments-complex-flex-items .container {
padding-top: 6rem !important;
}
.responsive-position {
position: relative;
@include media-breakpoint-up(md) {
position: absolute;
}
}
}
#commitments-paragraph-with-visual,
@ -429,13 +451,13 @@
.pictogram {
top: -3rem;
left: -2rem;
width: 8rem;
width: 6rem;
&-reversed {
top: -3rem;
right: -2rem;
left: auto;
width: 8rem;
width: 6rem;
}
}

View file

@ -9,6 +9,10 @@
min-height: 80vh;
overflow-x: hidden;
@include media-breakpoint-up(lg) {
overflow-x: visible;
}
.logo-40 {
max-width: calc(100% - 30px);
padding-top: 195px;
@ -973,9 +977,9 @@
.bg {
&-blue-dark-wood {
background-blend-mode: darken;
background-color: $primary;
background-image: url('@/images/common/wood-bg-big.jpg');
// background-blend-mode: darken;
// background-color: $primary;
background-image: url('@/images/common/wood-bg-blue.jpg');
background-position: center;
background-repeat: no-repeat;
background-size: cover;

View file

@ -7,11 +7,17 @@
height: 2rem;
}
.swiper-recruitment-offers img {
width: 100%;
.swiper-recruitment-offers {
img {
width: 100%;
@include media-breakpoint-up(md) {
width: 50%;
@include media-breakpoint-up(md) {
width: 50%;
}
}
.swiper-slide {
height: auto !important;
}
}
}
@ -28,7 +34,7 @@
}
}
&-news-corporate{
&-news-corporate {
.swiper-recruitment-news-corporates-pagination {
height: 25px;
}

View file

@ -1,4 +1,3 @@
.product-card {
.product-card-tag {
top: -5%;
@ -36,6 +35,10 @@
.product-card-bottom-part {
top: -1rem;
@include media-breakpoint-up(lg) {
min-height: 8.5rem;
}
.product-card-view-more {
margin-bottom: -1rem;
}

View file

@ -1,7 +1,6 @@
.testimonial-card {
.testimonial-img {
clip-path: polygon(60% .2vw,100% 0,100% calc(100% - .2vw),70% calc(100% - .35vw),40% 100%,0 calc(100% - .2vw),0 .2vw,30% 0);
clip-path: polygon(60% .2vw, 100% 0, 100% calc(100% - .2vw), 70% calc(100% - .35vw), 40% 100%, 0 calc(100% - .2vw), 0 .2vw, 30% 0);
&-wrapper {
@include media-breakpoint-up(lg) {
@ -36,4 +35,13 @@
min-height: 5rem;
}
}
.fa-play {
width: 2rem;
height: 2rem;
}
.video-link {
cursor: pointer;
}
}

View file

@ -24,19 +24,43 @@
.w#{$infix}-25 {
width: 25% !important;
}
.w#{$infix}-50 {
width: 50% !important;
}
.w#{$infix}-75 {
width: 75% !important;
}
.w#{$infix}-100 {
width: 100% !important;
}
.w#{$infix}-fit {
width: fit-content !important;
}
.h#{$infix}-25 {
height: 25% !important;
}
.h#{$infix}-50 {
height: 50% !important;
}
.h#{$infix}-75 {
height: 75% !important;
}
.h#{$infix}-100 {
height: 100% !important;
}
.h#{$infix}-fit {
height: fit-content !important;
}
@each $prop, $unit in (width: vw, height: vh) {
@each $size in [25, 50, 75, 100] {
.#{$unit}#{$infix}-#{$size} {

View file

@ -144,7 +144,7 @@ document.addEventListener("DOMContentLoaded", function () {
"swiper-recruitment-offers": {
modules: [Navigation, Keyboard, Pagination],
grabCursor: true,
slidesPerView: 1.3,
slidesPerView: 1,
initialSlide: 0,
spaceBetween: 10,
navigation: {
@ -165,6 +165,7 @@ document.addEventListener("DOMContentLoaded", function () {
576: {
slidesPerView: 2,
spaceBetween: 25,
slidesPerGroup: 2,
},
768: {
slidesPerView: 2,
@ -179,7 +180,7 @@ document.addEventListener("DOMContentLoaded", function () {
"swiper-recruitment-jobs": {
modules: [Navigation, Keyboard, Pagination],
grabCursor: true,
slidesPerView: 1.3,
slidesPerView: 1,
centeredSlides: true,
spaceBetween: 10,
navigation: {
@ -203,15 +204,16 @@ document.addEventListener("DOMContentLoaded", function () {
992: {
slidesPerView: 3,
initialSlide: 1,
slidesPerGroup: 3
},
},
},
"swiper-recruitment-news-corporates": {
modules: [Navigation, Keyboard, Pagination],
grabCursor: true,
slidesPerView: 3,
spaceBetween: 1,
slidesPerGroup: 3,
slidesPerView: 1,
spaceBetween: 40,
centerInsufficientSlides: true,
navigation: {
nextEl: ".swiper-recruitment-news-corporates-button-next",
prevEl: ".swiper-recruitment-news-corporates-button-prev",
@ -227,6 +229,16 @@ document.addEventListener("DOMContentLoaded", function () {
return "<button class=\"btn btn-tertiary rounded-circle border-0 mx-2 p-0 " + className + "\" title=\"Aller à la slide " + index + "\"></button>";
},
},
breakpoints: {
576: {
slidesPerView: 2,
slidesPerGroup: 2,
},
992: {
slidesPerView: 3,
slidesPerGroup: 3,
},
},
},
"swiper-main-slides": {
modules: [Autoplay, Navigation, Keyboard],
@ -283,7 +295,7 @@ document.addEventListener("DOMContentLoaded", function () {
"swiper-cards-commitments": {
modules: [Navigation],
grabCursor: true,
slidesPerView: 1.3,
slidesPerView: 1,
navigation: {
nextEl: "#swiper-cards-commitments ~ .swiper-cards-commitments-button-next",
prevEl: "#swiper-cards-commitments ~ .swiper-cards-commitments-button-prev",
@ -346,9 +358,9 @@ document.addEventListener("DOMContentLoaded", function () {
},
},
"swiper-recipes": {
modules: [Navigation],
modules: [Navigation, Pagination],
grabCursor: true,
slidesPerView: 1.5,
slidesPerView: 1,
centeredSlides: true,
spaceBetween: 20,
navigation: {
@ -363,6 +375,14 @@ document.addEventListener("DOMContentLoaded", function () {
992: {
slidesPerView: 3,
centeredSlides: false,
slidesPerGroup: 3,
},
},
pagination: {
el: ".swiper-recipe-pagination",
clickable: true,
renderBullet: function (index: number, className: string) {
return "<button class=\"" + className + "\" title=\"Aller à la slide " + (index + 1) + "\"></button>";
},
},
},
@ -489,7 +509,7 @@ document.addEventListener("DOMContentLoaded", function () {
"swiper-cards-breeder-pages": {
modules: [Navigation],
grabCursor: true,
slidesPerView: 1.3,
slidesPerView: 1,
spaceBetween: 40,
centerInsufficientSlides: true,
navigation: {
@ -546,6 +566,32 @@ document.addEventListener("DOMContentLoaded", function () {
document.querySelector("#swiper-videos .swiper-slide-next")?.setAttribute("inert", "true");
});
}
if (swiper.el.id === "swiper-testimonials") {
swiper.on("slideChange", function() {
updateTestimonialVideoModal(swiper.slides[swiper.activeIndex]);
});
}
}
function updateTestimonialVideoModal(currentSlide: any) {
const videoLinkElement = currentSlide.querySelector(".video-link") as HTMLAnchorElement;
if (!videoLinkElement) {
return;
}
const videoModal = document.querySelector("#testimonial-video-modal") as HTMLDivElement;
if (!videoModal) {
return;
}
const modalLink = document.querySelector(".video-inlaid") as HTMLAnchorElement;
if (!modalLink) {
return;
}
modalLink.setAttribute("href", String(videoLinkElement.dataset.videoLink));
const iframe = modalLink.querySelector("iframe");
if (!iframe) {
return;
}
iframe.setAttribute("src", String(videoLinkElement.dataset.videoLink));
}
function eventBtnPlayPause(swiper: Swiper, btnPlayPause: HTMLElement | null) {

View file

@ -213,10 +213,10 @@
<!-- BUTTONS -->
<div
v-if="contentParameters.swiper"
class="col-12 d-flex flex-column flex-md-row justify-content-center align-items-center w-100"
class="col-12 d-flex flex-column flex-md-row justify-content-center align-items-center w-75 w-md-100 mx-auto"
>
<a
class="content-btns btn btn-primary border-0 my-1 my-md-0 mx-md-1"
class="content-btns btn btn-primary border-0 my-1 my-md-0 mx-md-1 w-100 w-md-fit"
:href="getShowLegendRoute(legendsParameters.modelSelected?.slug as string)"
title="Accéder à la page de tous les produits de la gamme"
:style="'background-color:' + legendsParameters.modelSelected?.color"
@ -224,7 +224,7 @@
{{ (legendsParameters.modelSelected) ? textsParameters.btn1Label + " " + legendsParameters.modelSelected?.label : textsParameters.btn1Label }}
</a>
<a
class="content-btns btn btn-secondary border-0 my-1 my-md-0 mx-md-1"
class="content-btns btn btn-secondary border-0 my-1 my-md-0 mx-md-1 w-100 w-md-fit"
:href="getIndexContentRoute()"
title="Accéder à la page de tous les produits"
>
@ -245,8 +245,8 @@
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import Swiper from "swiper";
import { Navigation } from "swiper/modules";
import { defineOptions, nextTick, onMounted, ref, useAttrs, reactive, createApp } from "vue";
import type { App } from "vue";
import { createApp, defineOptions, nextTick, onMounted, reactive, ref, useAttrs } from "vue";
import route from "../../modules/route";
import trans from "../../modules/trans";
import parseLaravelErrorMessages from "./../../modules/parseLaravelErrorMessages";

View file

@ -5,11 +5,11 @@
>
<!-- TEXTS MOBILE -->
<div class="d-md-none col-12 col-md-7 col-xl-8 text-center">
<h2 ref="modelSubtitle">
<h2 ref="modelSubtitleMobile">
{{ textsParameters.subtitle }}
</h2>
<p
ref="modelDescription"
ref="modelDescriptionMobile"
v-html="textsParameters.description"
/>
</div>
@ -319,6 +319,8 @@ const filtersList = ref<HTMLDivElement|null>(null);
const childrenList = ref<HTMLDivElement|null>(null);
const modelSubtitle = ref<HTMLTitleElement|null>(null);
const modelDescription = ref<HTMLParagraphElement|null>(null);
const modelSubtitleMobile = ref<HTMLTitleElement|null>(null);
const modelDescriptionMobile = ref<HTMLParagraphElement|null>(null);
// * DATA
@ -457,6 +459,8 @@ function updateTexts(newTitle: string|null = null): void {
: filtersDetailsParameters.selectedModel;
modelSubtitle.value!.textContent = String(((currentModelSelected !== null) ? currentModelSelected : textsParameters).subtitle);
modelDescription.value!.innerHTML = String(((currentModelSelected !== null) ? currentModelSelected : textsParameters).description);
modelSubtitleMobile.value!.textContent = String(((currentModelSelected !== null) ? currentModelSelected : textsParameters).subtitle);
modelDescriptionMobile.value!.innerHTML = String(((currentModelSelected !== null) ? currentModelSelected : textsParameters).description);
let parentTitle = (filtersDetailsParameters.selectedChildModel !== null)
? filtersDetailsParameters.selectedModel?.label + ", "
: "";

View file

@ -15,57 +15,14 @@
<div class="card">
<div class="card-header fw-bold">{{ __('Connexion') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('bo.login') }}">
@csrf
<div class="row mb-3">
<label class="col-md-4 col-form-label text-md-end" for="email">{{ __('Adresse Email') }}</label>
<div class="col-md-6">
<input class="form-control @error('email') is-invalid @enderror" id="email" name="email"
type="email" value="{{ old('email') }}" autocomplete="email" autofocus required>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<div class="row">
<div class="col text-center">
<a class="btn btn-primary" href="{{ route('saml.login', ['uuid' => config('saml2.default_tenant_uuid')]) }}">
<span>{{ __('Connexion avec UWIL Support') }}</span>
<i class="fa-solid fa-arrow-right-from-bracket"></i>
</a>
</div>
<div class="row mb-3">
<label class="col-md-4 col-form-label text-md-end" for="password">{{ __('Mot de passe') }}</label>
<div class="col-md-6">
<input class="form-control @error('password') is-invalid @enderror" id="password" name="password"
type="password" autocomplete="current-password" required>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" id="remember" name="remember" type="checkbox"
{{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label user-select-none" for="remember">
{{ __('Se souvenir de moi') }}
</label>
</div>
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button class="btn btn-primary" type="submit">
<span>{{ __('Connexion') }}</span>
<i class="fa-solid fa-arrow-right-from-bracket"></i>
</button>
@if (Route::has('bo.password.request'))
<a class="btn btn-link" href="{{ route('bo.password.request') }}">
{{ __('Mot de passe oublié ?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>

View file

@ -40,7 +40,7 @@
@stack('styles')
@if (config('app.debug'))
<script nonce="{{ $nonce }}">
<script nonce="{{ $nonce ?? '' }}">
window.vueDebug = true;
</script>
@endif

View file

@ -8,20 +8,27 @@
@include('modules.breadcrumbs.breadcrumb-body')
</div>
<div class="border-start-0 border-end-0 border-bottom-0 border-secondary mt-2 border border-2">
<h5 class="card-title py-2">
<h5 class="card-title py-2 fw-bold">
{{ __('Bonjour :first_name :last_name !', [
'first_name' => auth('backend')->user()->first_name,
'last_name' => auth('backend')->user()->last_name,
]) }}
</h5>
<p class="card-text m-0">
<p class="card-text">
{{ __('Bienvenue dans le back-office, où vous pouvez gérer votre application web.') }}
</p>
<p class="card-text">
{{ __('Pour accéder à vos statistiques') }} :
<a class="btn btn-primary btn-sm" data-bs-toggle="tooltip" href="https://report.uwil.fr"
title="{{ __('Accéder à notre outil de ticketing') }}" target="blank">
{{ __('UWIL Report') }}
<i class="fa-solid fa-arrow-up-right-from-square ms-1"></i>
</a>
<br>
{{ __('Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil : ') }}
<a class="btn btn-primary btn-sm" data-bs-toggle="tooltip" href="https://support.uwil.fr/"
title="{{ __('Accéder à notre outil de ticketing') }}" target="blank">
{{ __('Uwil Support') }}
{{ __('UWIL Support') }}
<i class="fa-solid fa-arrow-up-right-from-square ms-1"></i>
</a>
</p>

View file

@ -21,7 +21,7 @@
src="{{ $discountModel->mobile_image_available ?? $discountModel->desktop_image_available }}"
alt="{{ __('Bon de réduction :name', ['name' => $discountModel->name]) }}">
</td>
<td class="text-center align-middle">@money($discountModel->value * 100)</td>
<td class="text-center align-middle">@money($discountModel->value)</td>
<td class="text-center align-middle">
<span class="badge text-bg-secondary">{{ $discountModel->updated_at->isoFormat('LLLL') }}</span>
</td>

View file

@ -0,0 +1,22 @@
@extends('fo.layout')
@section('title', __('Une erreur est survenue lors de la connexion.'))
@section('description', __('Il semble qu\'il y ait des erreurs pour répondre à votre demande.'))
@section('breadcrumb', 'no')
@section('bodyClass', 'bg-white-wood')
@section('content')
<div class="container my-5 py-5">
<div class="row">
<div class="col text-center">
<h1>{{ str(__('Une erreur est survenue lors de la connexion.'))->upper() }}</h1>
<h4 class="h4 my-4">
{{ __('Veuillez contacter le support.') }}
</h4>
<a class="btn btn-secondary" href="{{ route('fo.home.show') }}" title="{{ __('Accéder à la page d\'accueil') }}">
{{ str(__('retour à la page d\'accueil'))->upper() }}
</a>
</div>
</div>
</div>
@endsection

View file

@ -1,7 +1,6 @@
@use('\App\Enums\StaticPageType', 'StaticPageType')
<div class="row">
@if (!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product))
@if (!$staticPageModel->type->equals(StaticPageType::recipe) && !$staticPageModel->type->equals(StaticPageType::product))
{{-- SEO_TITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
@ -80,9 +79,10 @@
</fieldset>
</div>
@endif
@if (!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home))
@if (
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home))
{{-- TITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
@ -112,12 +112,13 @@
</fieldset>
</div>
@endif
@if (!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::legals) &&
!$staticPageModel->type->equals(StaticPageType::confidentiality) &&
!$staticPageModel->type->equals(StaticPageType::accessibility) &&
!$staticPageModel->type->equals(StaticPageType::selling))
@if (
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::legals) &&
!$staticPageModel->type->equals(StaticPageType::confidentiality) &&
!$staticPageModel->type->equals(StaticPageType::accessibility) &&
!$staticPageModel->type->equals(StaticPageType::selling))
{{-- SUBTITLE --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="h-100 border p-3">
@ -142,7 +143,7 @@
'model' => trans_choice('models.classes.static_page', 1),
]),
'min' => 3,
'max' => 255,
'max' => 500,
]),
'placeholder' => __(':field :inter:model', [
'field' => str(__('validation.custom.subtitle'))->ucfirst(),
@ -155,10 +156,11 @@
</fieldset>
</div>
@endif
@if (!$staticPageModel->type->equals(StaticPageType::recruitment) &&
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home))
@if (
!$staticPageModel->type->equals(StaticPageType::recruitment) &&
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home))
{{-- CONTENT --}}
<div class="col-12 mb-3">
<fieldset class="border p-3">
@ -189,15 +191,16 @@
</fieldset>
</div>
@endif
@if (!$staticPageModel->type->equals(StaticPageType::recipes) &&
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::products) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home) &&
!$staticPageModel->type->equals(StaticPageType::legals) &&
!$staticPageModel->type->equals(StaticPageType::confidentiality) &&
!$staticPageModel->type->equals(StaticPageType::accessibility) &&
!$staticPageModel->type->equals(StaticPageType::selling))
@if (
!$staticPageModel->type->equals(StaticPageType::recipes) &&
!$staticPageModel->type->equals(StaticPageType::recipe) &&
!$staticPageModel->type->equals(StaticPageType::products) &&
!$staticPageModel->type->equals(StaticPageType::product) &&
!$staticPageModel->type->equals(StaticPageType::home) &&
!$staticPageModel->type->equals(StaticPageType::legals) &&
!$staticPageModel->type->equals(StaticPageType::confidentiality) &&
!$staticPageModel->type->equals(StaticPageType::accessibility) &&
!$staticPageModel->type->equals(StaticPageType::selling))
{{-- PICTURE SECTION --}}
<div class="col-12 pb-3">
<fieldset class="h-100 border p-3">

View file

@ -89,39 +89,6 @@
</div>
</fieldset>
</div>
{{-- PASSWORD --}}
<div class="col-12 mb-3">
<fieldset class="h-100 border p-3">
<legend>{{ __('Mot de passe') }}</legend>
<div class="row">
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar-password', [
'id' => 'userPassword',
'label' => __('Mot de passe de l\':model', ['model' => __('models.classes.user')]),
'name' => 'password',
'hasWordCounter' => true,
'required' => !$userModel->exists,
'model' => null,
'helper' => __(
'Doît respecter certaines contraintes (8 caractères minimum, lettres, chiffres, caractères spéciaux).'),
])
</div>
<div class="col-12 col-md-6 mb-3">
@include('bo.partials.inputs.varchar-password', [
'id' => 'userPassword_confirmation',
'label' => __('Confirmation du mot de passe de l\':model', [
'model' => __('models.classes.user'),
]),
'name' => 'password_confirmation',
'hasWordCounter' => true,
'required' => !$userModel->exists,
'model' => null,
'helper' => __('Doît correspondre au mot de passe saisi précédemment.'),
])
</div>
</div>
</fieldset>
</div>
{{-- STATUS --}}
@can('changePublished', $userModel)
<div class="col-12 col-md-6 mb-3">
@ -145,20 +112,3 @@
<p><b>{{ __('* Champs obligatoires') }}</b></p>
</div>
</div>
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener("DOMContentLoaded", () => {
// If we edit the password, the confirmation is required.
const passwordInput = document.getElementById('userPassword');
const confirmPasswordInput = document.getElementById('userPassword_confirmation');
passwordInput.addEventListener('input', () => {
if (passwordInput.value !== '') {
confirmPasswordInput.required = true;
} else {
confirmPasswordInput.required = false;
}
})
});
</script>
@endpush

View file

@ -1,5 +1,5 @@
@push('scripts')
<script nonce="{{ $nonce }}">
<script nonce="{{ $nonce ?? '' }}">
document.addEventListener("DOMContentLoaded", () => {
const submit = document.getElementById('formSubmit')
submitClone = document.getElementById('formSubmitClone');

View file

@ -49,12 +49,11 @@
id="accept-cgu" name="ok_cgu" type="checkbox" required />
<label class="form-check-label w-fit" for="accept-cgu" role="button">
<span>{!! clean(__('J’accepte les conditions générales d’utilisation du site et autorise le Responsable de Traitement à traiter mes données personnelles conformément à la :startA Charte de confidentialité:endA.', [
'startA' =>
'<a class="link-body-emphasis" title="' .
__('Go to page :page', [
'page' => __('Charte de confidentialité'),
]) .
'" href="FIXME: privacy policy route">',
'startA' => sprintf(
'<a class="link-body-emphasis" target="_blank" title="%s" href="%s">',
__('Go to page :page', ['page' => __('Charte de confidentialité')]),
route('fo.policies.show')
),
'endA' => '</a>',
])) !!}</span>
</label>
@ -89,12 +88,11 @@
__(
'Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour la création de votre compte utilisateur. Pour connaître vos droits, vous pouvez consulter la :startA Charte de confidentialité:endA.',
[
'startA' =>
'<a class="link-body-emphasis" title="' .
__('Go to page :page', [
'page' => __('Charte de confidentialité'),
]) .
'" href="FIXME: privacy policy route">',
'startA' => sprintf(
'<a class="link-body-emphasis" target="_blank" title="%s" href="%s">',
__('Go to page :page', ['page' => __('Charte de confidentialité')]),
route('fo.policies.show')
),
'endA' => '</a>',
],
),

View file

@ -115,13 +115,13 @@
{{ __('© Copyright :appname', ['appname' => config('app.name')]) }}</li>
<li class="list-inline-item me-0">-</li>
<li class="list-inline-item me-0">
<a href="#FIXME:legals"
<a href="{{ route('fo.legals.show') }}"
title="{{ __('Go to page :page', ['page' => 'Mentions légales et CGU Charte de confidentialité']) }}">
{{ __('Mentions légales et CGU Charte de confidentialité') }}</a>
</li>
<li class="list-inline-item me-0">-</li>
<li class="list-inline-item me-0">
<a href="#FIXME:confidentiality"
<a href="{{ route('fo.conditions.show') }}"
title="{{ __('Go to page :page', ['page' => 'CGV']) }}">{{ __('CGV') }}</a>
</li>
<li class="list-inline-item me-0">-</li>

View file

@ -27,7 +27,7 @@
'line2' => __('Dès aujourd’hui'),
'line2Class' => 'fs-4',
'content' => __('Spécial étudiant, Spécial famille, Spécial membre'),
'promoAmount' => 770 //FIXME: call mesbr,
'promoAmount' => $discountsTotal
])
@include('club.partials.card-club-home', [
'outterClass' => 'm-3',
@ -67,11 +67,11 @@
<section class="container-fluid d-sm-none">
<div class="row my-3">
<div class="col d-flex flex-column align-items-center">
<a class="btn btn-secondary btn-lg flex-shrink-1 mb-3" href="#FIXME:register"
<a class="btn btn-secondary btn-lg flex-shrink-1 mb-3" href="{{ route('club.register') }}"
title="{{ __('Go to page :page', [
'page' => __('Inscription'),
]) }}">{{ __('Je m\'inscris') }}</a>
<a class="link-light link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="#FIXME:login"
<a class="link-light link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover" href="{{ route('club.login') }}"
title="{{ __('Go to page :page', [
'page' => __('Connexion'),
]) }}">{{ __('J\'ai déjà un compte') }}</a>

View file

@ -64,7 +64,7 @@
<div class="text-bg-white rounded-5 fs-5 p-5 pt-0 text-center">
<h2 class="section-title text-uppercase f-bourton-base">
<span class="text-bg-warning">{{ __('Économiser aujourd’hui') }}</span><span
class="text-bg-danger">@money($discountsTotal * 100)</span>
class="text-bg-danger">@money($discountsTotal)</span>
</h2>
<span
class="d-block fw-bold mb-3">{{ __('En bons de réduction sur une sélection de produits Le Gaulois') }}</span>
@ -80,7 +80,7 @@
<div class="d-none d-md-block text-bg-white col-12 mt-5 pb-5 text-center">
<h2 class="section-title text-uppercase f-bourton-base d-none d-md-inline-flex">
<span class="text-bg-warning">{{ __('Économiser aujourd’hui') }}</span>
<span class="text-bg-danger">@money($discountsTotal * 100)</span>
<span class="text-bg-danger">@money($discountsTotal)</span>
</h2>
<span class="d-block fs-5 fw-bold mb-5">
{{ __('En bons de réduction sur une sélection de produits Le Gaulois') }}

View file

@ -26,7 +26,7 @@
<div class="col-7">
<div
class="card-body d-flex flex-column justify-content-between align-items-start rounded-5 rounded-start-0 text-bg-white">
<span class="text-bg-danger f-bourton-base fw-bold fs-1 px-2 py-1">@money($discount->value * 100)</span>
<span class="text-bg-danger f-bourton-base fw-bold fs-1 px-2 py-1">@money($discount->value)</span>
<p class="card-text f-bourton-base text-tertiary text-start fs-6 my-1">{{ $discount->name }}</p>
@if (!isset($discount->used) || !$discount->used)
@if (request()->routeIs('club.home.show'))

View file

@ -1,4 +1,4 @@
<div class="container mt-5">
<div class="mb-lg-5 container mt-5">
<div class="navigation-card bg-light position-relative line-border-small light-card-content text-primary mx-auto mt-3 px-3 py-4">
<nav class="d-flex justify-content-md-center" aria-label="breadcrumb">
<ol class="breadcrumb text-primary">
@ -11,30 +11,31 @@
</nav>
<p class="fs-5 text-md-center pr-3 text-start">
Depuis <strong> 40 ans</strong>, Le Gaulois s'engage à proposer des produits <strong>100% origine France</strong> avec
des volailles
nées, élevées et
préparées sur notre territoire. 40 ans de convivialité et de plaisir à la française, <strong>à partager avec vous
!</strong> Pendant
cette année festive, découvrez <strong>nos jeux et nos surprises</strong>.
{!! clean(
__(
'Depuis 40 ans, Le Gaulois s\'engage à proposer des produits <strong>100% origine France</strong> avec des <strong>volailles nées, élevées et préparées</strong> sur notre territoire. <br>
<strong>40 ans de convivialité et de plaisir à la française, à partager avec vous !</strong> <br>
Pendant cette année festive, découvrez <strong>nos jeux et nos surprises</strong>.',
),
) !!}
</p>
<div class="d-flex flex-column flex-md-row justify-content-center mt-4 gap-4">
<div class="text-md-start text-center">
<a class="btn text-uppercase w-100 w-md-fit btn-cotillons f-bourton-base fw-medium px-md-3 px-0 py-2 text-white"
href="#nos-40-annees">
Nos 40 années
{{ __('Nos 40 années') }}
</a>
</div>
<div class="text-md-start text-center">
<a class="btn text-uppercase w-100 w-md-fit btn-cotillons f-bourton-base fw-medium px-md-3 px-0 py-2 text-white"
href="#le-jeu-des-40-ans">
Jouez avec nous !
{{ __('Jouez avec nous !') }}
</a>
</div>
<div class="text-md-start text-center">
<a class="btn text-uppercase w-100 w-md-fit btn-cotillons f-bourton-base fw-medium px-md-3 px-0 py-2 text-white"
href="#encore-plus-de-cadeaux">
Encore + de cadeaux !
{{ __('Encore + de cadeaux !') }}
</a>
</div>

View file

@ -1,11 +1,15 @@
<h2 class="fs-1 f-bourton-base text-primary text-center">L'anniversaire de <span class="bg-danger text-white shadow-sm">68
millions</span>
de Gaulois
!</h2>
<p class="fs-5 text-primary py-md-4 py-2 text-center">Pour notre 40e anniversaire, nous célébrons avec nos 68 millions de
Gaulois, notre
attachement pour des
produits français et
authentiques, qui reflètent nos valeurs de qualité, accessibilité et de transparence.
<h2 class="fs-1 f-bourton-base text-primary text-center">
{{ __('L\'anniversaire de') }}
<span class="bg-danger text-white shadow-sm">
{{ __('68 millions') }}
</span>
{{ __('de Gaulois !') }}
</h2>
<p class="fs-5 text-primary py-md-4 py-2 text-center">
{!! clean(
__(
'Pour notre <strong>40e anniversaire</strong>, nous célébrons avec nos <strong>68 millions de Gaulois</strong>, notre attachement pour des produits <strong>français et authentiques</strong>, qui reflètent nos <strong>valeurs de qualité, accessibilité et de transparence.</strong>',
),
) !!}
</p>
<h3 class="text-primary fs-3 text-center">Bon anniversaire à tous nos Gaulois !</h3>
<h3 class="text-primary fs-3 text-center">{{ __('Bon anniversaire à tous nos Gaulois !') }}</h3>

View file

@ -11,7 +11,5 @@
</div>
<img class="object-fit-fill" id="drapeau-france"
src="{{ Vite::asset('resources/assets/images/page-des-40-ans/section2/drapeau.svg') }}" alt="{{ __('Photo drapeau France') }}">
</div>
<small class="text-primary f-catamaran credit-photo">Crédit photo -</small>
</div>

View file

@ -2,7 +2,7 @@
<div class="bg-confettis-without-min-height position-absolute h-100 w-100 z-1 start-0 top-0"></div>
<div class="bg-blue-dark-wood">
<div class="z-2 position-relative container-fluid container py-4" id="encore-plus-de-cadeaux">
<h3 class="fs-2 pt-5 text-center text-white">Encore + de cadeaux à gagner</h3>
<h3 class="fs-2 pt-5 text-center text-white">{{ __('Encore + de cadeaux à gagner') }}</h3>
<div class="py-5">
<div class="row gx-4 gy-5">
@ -11,8 +11,8 @@
<div class="gradient-yellow-card bg-gradient-yellow position-relative line-border-small w-fit p-1">
<div class="">
<div class="bg-light position-relative line-border-small p-4">
<h4 class="text-primary text-center">Collectez des points et choisissez vos cadeaux dans notre
boutique
<h4 class="text-primary text-center">
{{ __('Collectez des points et choisissez vos cadeaux dans notre boutique') }}
</h4>
<div class="row">
<div class="col-md-6 d-flex flex-column">
@ -21,8 +21,10 @@
src="{{ Vite::asset('resources/assets/images/page-des-40-ans/section4/sticker-boutique.png') }}"
alt="{{ __('Image de sticker de la boutique') }}">
</div>
<p class="f-bourton-base fs-5 text-uppercase text-primary text-center">1€ dépensé = <br /> 1
point collecté</p>
<p class="f-bourton-base fs-5 text-uppercase text-primary text-center">
{{ __('1€ dépensé = ') }}<br />
{{ __('1 point collecté') }}
</p>
</div>
<div class="col-md-6">
@ -45,8 +47,9 @@
</div>
<p class="f-bourton-base fs-5 text-uppercase text-primary text-center">2 paliers, <br /> de
nombreux cadeaux
<p class="f-bourton-base fs-5 text-uppercase text-primary text-center">
{{ __('2 paliers, ') }}<br />
{{ __('de nombreux cadeaux') }}
</p>
</div>
@ -58,8 +61,9 @@
</div>
<a class="button-gradient-yellow btn text-uppercase text-primary bg-gradient-yellow"
href="https://www.boutiquelegaulois.fr" target="_blank">Découvrez
notre boutique</a>
href="https://www.boutiquelegaulois.fr" target="_blank">
{{ __('Découvrez notre boutique') }}
</a>
<div class="image-cadeau-rouge align-self-center">
<img class="object-fit-contain h-100 w-100"
@ -74,24 +78,28 @@
<div class="bg-gradient-yellow gradient-yellow-card position-relative line-border-small w-fit p-1">
<div class="">
<div class="bg-light position-relative line-border-small p-4">
<h4 class="text-primary text-center">Trouvez les magnets dorés <br /> et remportez une surpise !
<h4 class="text-primary text-center">
{{ __('Trouvez les magnets dorés') }}<br />
{{ __('et remportez une surpise !') }}
</h4>
<p class="f-bourton-base text-primary fw-medium fs-5 text-uppercase mt-3 text-center">
Pour ses 40 ans, le gaulois a caché 94 magnets dorés <br /> dans ses étuis de panés
{{ __('Pour ses 40 ans, le gaulois a caché 94 magnets dorés') }}<br />
{{ __('dans ses étuis de panés') }}
</p>
<ol class="text-primary ordered-list-centered-with-number">
<li class="lh-lg">
<strong>Je découvre</strong> un Magnet doré
<strong>{{ __('Je découvre') }}</strong> {{ __('un magnet doré') }}
</li>
<li>
<strong>Je gagne</strong> une carte de France collector 40 ans créée par un jeune artise
français et une collection complète de magnets dorés !
<strong>{{ __('Je gagne') }}</strong>
{{ __('une carte de France collector 40 ans créée par un jeune artise français et une collection complète de magnets dorés !') }}
</li>
</ol>
<p class="text-primary fs-4 fw-semibold f-bakerie-rough text-center">Bonne recherche à nos 68
millions de Gaulois !</p>
<p class="text-primary fs-4 fw-semibold f-bakerie-rough text-center">
{{ __('Bonne recherche à nos 68millions de Gaulois !') }}
</p>
</div>
</div>

View file

@ -32,13 +32,13 @@
title="{{ __('Go to page :page', ['page' => 'Nos produits']) }}">{{ __('Nos produits') }}</a>
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.recipes.index') }}"
title="{{ __('Go to page :page', ['page' => 'Nos recettes']) }}">{{ __('Nos recettes') }}</a>
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="#FIXME:nosengagements"
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.commitments.brand') }}"
title="{{ __('Go to page :page', ['page' => 'Nos engagements']) }}">{{ __('Nos engagements') }}</a>
</div>
<div class="col col-lg-2 d-none d-sm-flex flex-column align-items-baseline">
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="#FIXME:leselevages"
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.breeding.index') }}"
title="{{ __('Go to page :page', ['page' => 'Les élevages']) }}">{{ __('Les élevages') }}</a>
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="#FIXME:brand"
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.brand.story') }}"
title="{{ __('Go to page :page', ['page' => 'Notre marque']) }}">{{ __('Notre marque') }}</a>
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.recruitment.show') }}"
title="{{ __('Go to page :page', ['page' => 'Recrutement']) }}">{{ __('Recrutement') }}</a>
@ -48,8 +48,8 @@
<div class="col col-lg-2 ms-lg-auto d-none d-sm-flex flex-column align-items-baseline">
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="{{ route('fo.contact.show') }}"
title="{{ __('Go to page :page', ['page' => 'Nous contacter']) }}">{{ __('Nous contacter') }}</a>
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="#FIXME:faq"
title="{{ __('Go to page :page', ['page' => 'Faq']) }}">{{ __('Faq') }}</a>
{{-- <a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="#FIXME:faq"
title="{{ __('Go to page :page', ['page' => 'Faq']) }}">{{ __('Faq') }}</a> --}}
<a class="fs-5 text-uppercase btn btn-link text-decoration-none py-2" href="https://www.legauloisprofessionnel.fr"
title="{{ __('Aller sur le site Le Gaulois Professionel') }}" target="_blank">{{ __('Le Gaulois Professionel') }}</a>
</div>

View file

@ -18,6 +18,7 @@
<a class="cn-cookie-link" href="#"
title="{{ __('Go to page :page', ['page' => 'Gestion des cookies']) }}">{{ __('Gestion des cookies') }}</a>
</li>
{{-- FIXME:
<li class="list-inline-item me-0">-</li>
<li class="list-inline-item me-0">
<a href="FIXME:#plandusite" title="{{ __('Go to page :page', ['page' => 'Plan du site']) }}">{{ __('Plan du site') }}</a>
@ -26,5 +27,5 @@
<li class="list-inline-item me-0">
<a href="{{ route('fo.accessibility.show') }}" title="{{ __('Go to page :page', ['page' => 'accessibilité']) }}">{{ __('Accessibilité') }}</a>
<span>{{ __(' : partiellement conforme') }}</span>
</li>
</li> --}}
</ul>

View file

@ -37,7 +37,7 @@
{{ __('Devenez un Gaulois ++,') }}<br>{{ __(' et profitez de tous les avantages') }}
</p>
<a class="card bg-primary position-relative text-decoration-none mx-auto p-3 pb-5"
href="#CHANGEME: connexion au club" title="{{ __('Accéder au club des Gaulois') }}">
href="{{ route('club.home.show') }}" title="{{ __('Accéder au club des Gaulois') }}">
<div class="row hstack mb-3">
<div class="col-5 d-flex justify-content-center">
<img class="img-fluid w-75" src="{{ Vite::asset('resources/assets/images/header/club-logo.png') }}"

View file

@ -48,7 +48,7 @@
{{-- DEBUG --}}
@if (config('app.debug'))
<script @if (!empty($nonce)) nonce="{{ $nonce }}" @endif>
<script nonce="{{ $nonce ?? '' }}">
window.vueDebug = true;
</script>
@endif

View file

@ -29,9 +29,7 @@
],
[
'name' => __('L\'élevage de volailles'),
'link' => route(
'fo.breeding.show',
$breedingPages->where('type', \App\Enums\StaticPageType::breedingPoultry)->first()),
'link' => route('fo.breeding.show', 'slug'),
],
[
'name' => __('Le métier d\'élevage de volailles'),

View file

@ -8,35 +8,40 @@
@section('content')
<section id="breeding-article">
{{-- HEADER --}}
<section class="position-relative mb-xl-0 mb-3" id="breeding-article-header">
<div class="position-absolute w-100 h-100 start-0 z-0" id="breeding-article-background"></div>
<div class="row w-100 container mx-auto pb-5">
<div class="col-12 col-xl-6 col-xxl-8 position-relative z-1">
<section id="header-banner" @class([
'position-relative header-line-border',
'mb-5 mb-xl-0' => isset($contentAstride) && $contentAstride,
])>
<div class="position-absolute w-100 h-100 start-0 z-0" id="header-background"></div>
<div class="row w-100 pb-lg-5 container mx-auto pb-0">
<div class="col-12 col-xl-6 position-relative z-1">
@include('modules.breadcrumbs.breadcrumb-body', ['brParam' => [$staticPageModel, $newsBreedingModel]])
<h1 class="text-break my-3">{{ $newsBreedingModel->title }}</h1>
</div>
<div class="col-12 col-md-6 position-relative z-1">
<ul class="d-flex justify-content-start align-items-baseline p-0">
<li class="me-2">
<p class="text-uppercase text-bg-success f-bourton-base fs-5 px-2 py-1">{{ $staticPageModel->title }}
</p>
</li>
<li>
@include('fo.partials.button-share', [
'link' => route('fo.breeding.article.show', [$staticPageModel, $newsBreedingModel]),
'elementName' => __('cet article'),
])
</li>
</ul>
<hgroup>
<div class="d-flex justicy-content-center align-items-center">
<h1 class="my-3">{{ $newsBreedingModel->title }}</h1>
</div>
<ul class="d-flex justify-content-start align-items-baseline p-0">
<li class="me-2">
<p class="text-uppercase text-bg-success f-bourton-base fs-5 px-2 py-1">{{ $staticPageModel->title }}
</p>
</li>
<li>
@include('fo.partials.button-share', [
'link' => route('fo.breeding.article.show', [$staticPageModel, $newsBreedingModel]),
'elementName' => __('cet article'),
])
</li>
</ul>
</hgroup>
</div>
<div class="d-none d-xl-block col-6 col-xxl-4">
<div class="breeding-article-image-wrapper">
<div class="header-image-wrapper">
<img class="img-fluid" src="{{ asset($newsBreedingModel->picture) }}" title="{{ $newsBreedingModel->picture_title }}"
alt="{{ $newsBreedingModel->picture_alt }}">
</div>
</div>
<div class="d-xl-none col-12 col-md-8 position-relative z-1 mx-auto mt-4">
<div class="breeding-article-image-wrapper">
<div class="col-12 col-md-8 position-relative z-1 mx-auto mt-4">
<div class="d-xl-none header-image-wrapper">
<img class="img-fluid" src="{{ asset($newsBreedingModel->picture) }}" title="{{ $newsBreedingModel->picture_title }}"
alt="{{ $newsBreedingModel->picture_alt }}">
</div>
@ -44,7 +49,7 @@
</div>
</section>
<section class="container mt-3">
<div class="row">
<div class="row py-5">
<article class="col me-4">
<h2 class="text-break">{{ $newsBreedingModel->subtitle }}</h2>
<div class="ck-content">

View file

@ -20,10 +20,11 @@
'title' => 'L\'élevage des volailles',
'text' => nl2br(
__(
'Face aux préoccupations des consommateurs sur le bien-être animal, Le Gaulois vous dit tout sur ses :strongStartéleveurs partenaires:strongEnd et ses conditions d:strongStart\'élevages de volailles.:strongEnd Chaque jour, nous collaborons avec les éleveurs partenaires engagés dans la démarche éthique et responsable pour améliorer le confort de nos volailles. Chez les éleveurs partenaires Le Gaulois, la protection animale ne cesse d\'être l\'enjeu majeur.',
'Face aux préoccupations des consommateurs sur le bien-être animal, Le Gaulois vous dit tout sur ses :strongStartéleveurs partenaires:strongEnd et ses :strongStartconditions d\'élevages de volailles.:strongEnd :br Chaque jour, nous collaborons avec les éleveurs partenaires engagés dans la :strongStartdémarche éthique et responsable:strongEnd pour améliorer le confort de nos volailles. Chez les éleveurs partenaires Le Gaulois, la :strongStartprotection animale:strongEnd ne cesse d\'être l\'enjeu majeur.',
[
'strongStart' => '<strong>',
'strongEnd' => '</strong>',
'br' => '<br>',
])),
])

View file

@ -33,10 +33,11 @@
'title' => 'L\'élevage des volailles',
'text' => nl2br(
__(
'Face aux préoccupations des consommateurs sur le bien-être animal, Le Gaulois vous dit tout sur ses :strongStartéleveurs partenaires:strongEnd et ses conditions d:strongStart\'élevages de volailles.:strongEnd Chaque jour, nous collaborons avec les éleveurs partenaires engagés dans la démarche éthique et responsable pour améliorer le confort de nos volailles. Chez les éleveurs partenaires Le Gaulois, la protection animale ne cesse d\'être l\'enjeu majeur.',
'Face aux préoccupations des consommateurs sur le bien-être animal, Le Gaulois vous dit tout sur ses :strongStartéleveurs partenaires:strongEnd et ses :strongStartconditions d\'élevages de volailles.:strongEnd :br Chaque jour, nous collaborons avec les éleveurs partenaires engagés dans la :strongStartdémarche éthique et responsable:strongEnd pour améliorer le confort de nos volailles. Chez les éleveurs partenaires Le Gaulois, la :strongStartprotection animale:strongEnd ne cesse d\'être l\'enjeu majeur.',
[
'strongStart' => '<strong>',
'strongEnd' => '</strong>',
'br' => '<br>',
])),
])
</section>

View file

@ -129,21 +129,6 @@
'background_color' => 'white',
])
{{-- PARAGRAPH WITH PICTURE --}}
@php
$newsCategory = new stdClass();
$newsCategory->title = __('Actu');
$newsModel = new stdClass();
$newsModel->title = __('découvrez notre charte nutritionnelle pour alliers plaisir et santé');
$newsModel->slug = str($newsModel->title)->slug();
$newsModel->thumbnail = Vite::asset('resources/assets/images/commitments/pictograms/picto-medications.svg');
$newsModel->thumbnail_alt = __('Pictogramme de plusieurs médicaments.');
$newsModel->thumbnail_title = __('Pictogramme d’une diminution de l’utilisation des antibiotiques.');
$newsModel->date = now()->subDays(rand(0, 31));
$newsModel->link = 'FIXME: route to the news';
$newsModel->newsCategory = $newsCategory;
$newsModel->updated_at = now();
@endphp
@include('fo.partials.commitments.paragraph-with-visual', [
'title' => __('découvrez notre charte nutrionnelle pour allier plaisir et santé'),
'text' => __(
@ -154,7 +139,6 @@
'picture_alt' => __('Photo d’une famille prenant le repas du midi.'),
'picture_title' => __('Photo d’une famille prenant le repas du midi.'),
'reversedMobile' => true,
'newsModel' => $newsModel,
])
{{-- BANNER TEXT --}}
@php

View file

@ -125,22 +125,28 @@
])
{{-- PARAGRAPH WITH PICTURE --}}
@php
$newsCategory = new stdClass();
$newsCategory->title = __('Actu');
$newsModel = new stdClass();
$newsModel->title = __('découvrez notre charte nutritionnelle pour alliers plaisir et santé');
$newsModel->slug = str($newsModel->title)->slug();
$newsModel->thumbnail = Vite::asset('resources/assets/images/commitments/pictograms/picto-medications.svg');
$newsModel->thumbnail_alt = __('Pictogramme de plusieurs médicaments.');
$newsModel->thumbnail_title = __('Pictogramme d’une diminution de l’utilisation des antibiotiques.');
$newsModel->date = now()->subDays(rand(0, 31));
$newsModel->link = 'FIXME: route to the news';
$newsModel->newsCategory = $newsCategory;
$newsModel->updated_at = now();
$videoID = '63RGcX7_MCM';
@endphp
<div class="modal fade translate-middle top-50 start-50" id="mecenat-chirurgie-video-modal" aria-labelledby="mecenatChirurgieVideoModalLabel"
aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button class="btn-close" data-bs-dismiss="modal" type="button" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="video-inlaid ratio ratio-16x9" type="youtube" href="https://www.youtube.com/embed/{{ $videoID }}">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal" type="button">{{ __('Fermer') }}</button>
</div>
</div>
</div>
</div>
@include('fo.partials.commitments.paragraph-with-visual', [
'title' => __('2021, nos collaborateurs ont du cœur'),
'isVideoModal' => true,
'text' => nl2br(
__(
'Depuis 2021, Le Gaulois soutient l’:strongStartassociation Mécénat Chirurgie Cardiaque:strongEnd pour sauver des enfants en finançant des opérations d’enfants atteint de malformation cardiaque. :strongStartCourse à pied, vélo, marche, randonnée,:strongEnd les kilomètres parcourus sont compilés par une application sportive tout au long de l’année pour récolter un maximum de fonds pour l’association.',
@ -176,13 +182,12 @@
'strongEnd' => '</strong>',
])),
'background_color' => 'light',
'video_id' => '63RGcX7_MCM',
'video_id' => $videoID,
'picto' => Vite::asset('resources/assets/images/commitments/common/logo-mecenat.jpg'),
'picto_alt' => __(
'Logo de Mécénat Chirurgie Cardiaque, un soutien aux initiatives culturelles et sociales pour promouvoir la solidarité et l\'engagement'),
'picto_title' => __('Logo de Mécénat Chirurgie Cardiaque, enfant du monde'),
'reversedMobile' => true,
'newsModel' => $newsModel,
])
{{-- OTHER COMMITMENTS --}}
@include('fo.partials.commitments.other-commitments', [

View file

@ -107,7 +107,7 @@
'title' => __('stop à la déforestation, halte au soja non responsable'),
'text' => nl2br(
__(
'Chez Le Gaulois, pour assurer :strongStartl’apport protéique:strongEnd et assurer un équilibre nutritionnel de nos volailles, nous les alimentons avec du soja. C’est la légumineuse la plus riche en protéines et en acides aminés essentiels ! Conscient que la culture du Soja importée est assujettie à de nombreux questionnements, notamment son impact sur la déforestation.',
'Chez Le Gaulois, pour assurer :strongStartl’apport protéique:strongEnd et assurer un :strongStartéquilibre nutritionnel de nos volailles:strongEnd, nous les alimentons avec du :strongStartsoja:strongEnd. C’est la :strongStartlégumineuse la plus riche en protéines et en acides aminés essentiels !:strongEnd Conscient que la culture du Soja importée est assujettie à de nombreux questionnements, notamment son impact sur la :strongStartdéforestation.:strongEnd',
[
'strongStart' => '<strong>',
'strongEnd' => '</strong>',
@ -135,11 +135,17 @@
'Conscient de son rôle, Le Gaulois s ‘est engagé dans une démarche continue de réduction de ses emballages et d’amélioration de leur recyclabilité, tout en garantissant la sécurité alimentaire.') .
'</br>' .
__(
'<ul class="mb-3 p-0">Depuis fin 2023, près de 80% de nos emballages sont responsables :<li class="ms-4">soit intégrant de la matière recyclée</li><li class="ms-4">soit en étant recyclables</li></ul>') .
__('D’ici fin 2025, nous ambitionnons de passer à près de 95% d’emballages responsables.') .
'<ul class="mb-3 p-0">Depuis fin 2023, près de :strongStart80% de nos emballages sont responsables:strongEnd :<li class="ms-4">soit intégrant de la matière recyclée</li><li class="ms-4">soit en étant recyclables</li></ul>',
['strongStart' => '<strong>', 'strongEnd' => '</strong>']) .
__(
'<p>D’ici fin 2025, nous ambitionnons de passer à près de :strongStart95% d’emballages responsables.:strongEnd</p>',
[
'strongStart' => '<strong>',
'strongEnd' => '</strong>',
]) .
'</br>' .
__(
':divStart:image:hgroupStart:strongStartLe saviez-vous ?:strongEnd 100% des emballages cartons Le Gaulois sont déjà issus de cartons recyclés et certifiés FSC, garantissant une gestion responsable des forêts, et plus de 60% des barquettes de volaille Le Gaulois sont recyclables ou intégrant au moins 50% de matière recyclée.:hgroupEnd:divEnd',
':divStart:image:hgroupStart:strongStartLe saviez-vous ?:strongEnd 100% des emballages cartons Le Gaulois sont déjà issus de :strongStartcartons recyclés et certifiés FSC:strongEnd, garantissant une gestion responsable des forêts, et :strongStartplus de 60% des barquettes:strongEnd de volaille Le Gaulois sont recyclables ou intégrant :strongStartau moins 50% de matière recyclée.:hgroupEnd:divEnd:strongEnd',
[
'image' =>
'<img src="' .
@ -190,6 +196,7 @@
// Item 4
$complexItem4 = new stdClass();
$complexItem4->title = str(__('moins de plastique'))->upper();
$complexItem4->text = str(__('minimiser notre empreinte carbone et agir sur le changement climatique'));
$complexItem4->picto = 'resources/assets/images/commitments/pictograms/picto-plastic-decrease.svg';
$complexItem4->picto_alt = __('Pictogramme d’un sac plastique avec l’estampille de recyclabilité');
$complexItem4->picto_title = __('Pictogramme sur la diminution de plastique');

View file

@ -6,13 +6,13 @@
@section('bg-offset', true)
@section('content')
<section id="home" class="overflow-hidden">
<section class="overflow-hidden" id="home">
{{-- HOT NEWS --}}
<div id="hot-news" @class([
'd-none position-fixed top-50 end-0 translate-middle-y bottom-left-shadow z-3',
'd-xl-block' => !cache('hotNewsIsDisplayed'),
])>
<div class="line-border-small py-3 bg-white">
<div class="line-border-small bg-white py-3">
<div class="bg-primary position-absolute w-100 h-100 z-2 start-0 top-0 bg-opacity-50" id="hot-news-loader">
<div class="position-absolute start-50 top-50 translate-middle">
<div class="spinner-border" role="status">
@ -20,7 +20,7 @@
</div>
</div>
</div>
<button class="btn-close position-absolute start-0 top-0 pt-3 ms-2 pe-2 mt-2 bg-white opacity-100" id="close-hot-news"
<button class="btn-close position-absolute start-0 top-0 ms-2 mt-2 bg-white pe-2 pt-3 opacity-100" id="close-hot-news"
aria-label="Close"></button>
@include('fo.partials.hot-news')
</div>
@ -31,19 +31,16 @@
<div class="swiper swiper-main-slides overflow-visible" id="swiper-main-slides">
<div class="swiper-wrapper w-fit">
@foreach ($mainSlideModels as $mainSlideModel)
<div class="swiper-slide h-auto pb-5 pb-md-0" style="background-color:{{ $mainSlideModel->color_block }}">
<div class="swiper-slide pb-md-0 h-auto pb-5" style="background-color:{{ $mainSlideModel->color_block }}">
<div class="swiper-background d-flex justify-content-center align-items-center">
<img src="{{ asset($mainSlideModel->background) }}"
title="{{ $mainSlideModel->background_title }}"
<img src="{{ asset($mainSlideModel->background) }}" title="{{ $mainSlideModel->background_title }}"
alt="{{ $mainSlideModel->background_alt }}">
</div>
<div
class="card d-flex flex-column-reverse flex-sm-row align-items-center align-items-sm-start justify-content-center align-items-md-center flex-row border-0 bg-transparent">
@if ($mainSlideModel->picture)
<img class="card-picture img-fluid ms-md-0 ms-sm-2 ms-0"
src="{{ asset($mainSlideModel->picture) }}"
title="{{ $mainSlideModel->picture_title }}"
alt="{{ $mainSlideModel->picture_alt }}">
<img class="card-picture img-fluid ms-md-0 ms-sm-2 ms-0" src="{{ asset($mainSlideModel->picture) }}"
title="{{ $mainSlideModel->picture_title }}" alt="{{ $mainSlideModel->picture_alt }}">
@endif
<div @class([
'card-body position-relative p-0',
@ -106,14 +103,13 @@
<img src="{{ Vite::asset('resources/assets/images/common/arrow-brown.svg') }}"
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</button>
<img class="w-100 d-none d-xl-block"
src="{{ Vite::asset('resources/assets/images/home/bg-slider-wood.png') }}"
<img class="w-100 d-none d-xl-block" src="{{ Vite::asset('resources/assets/images/home/bg-slider-wood.png') }}"
alt="{{ __('Footer imitation bois du slider') }}">
</section>
@endif
{{-- HOT NEWS DESKTOP --}}
<div class="position-relative d-block d-xl-none" id="hot-news-desktop">
<div class="position-absolute start-0 wood-background w-100"></div>
<div class="position-absolute wood-background w-100 start-0"></div>
<div class="d-block d-xl-none hot-news-position position-relative bottom-left-shadow mx-auto">
<div class="line-border-small bg-white">
@include('fo.partials.hot-news')
@ -165,11 +161,9 @@
<div class="swiper-wrapper w-fit">
@foreach ($demarcheSlideModels as $demarcheSlideModel)
<div class="swiper-slide position-relative p-lg-5 pb-lg-0 h-auto overflow-hidden p-0">
<div
class="slide-background line-border-medium position-absolute start-50 translate-middle-x w-100">
<div class="slide-background line-border-medium position-absolute start-50 translate-middle-x w-100">
<img src="{{ Vite::asset('resources/assets/images/home/bg-demarche-slider.jpg') }}"
title="{{ __('Image de fond du carrousel') }}"
alt="{{ __('Paysage de champs') }}">
title="{{ __('Image de fond du carrousel') }}" alt="{{ __('Paysage de champs') }}">
</div>
<div class="h-100 container">
<div class="slide-card position-relative h-100">
@ -181,8 +175,7 @@
alt="#FIXME:alt de l'image de la démarche">
</a>
<div class="slide-content position-relative pt-lg-0 pt-2">
<div
class="line-border-medium bg-light position-absolute w-100 h-100 start-0 top-0">
<div class="line-border-medium bg-light position-absolute w-100 h-100 start-0 top-0">
</div>
<div class="slide-content-texts position-relative z-1 p-lg-5 p-3">
<h2 class="text-secondary fs-2">
@ -216,14 +209,12 @@
<button
class="swiper-button swiper-button-prev-custom swiper-demarche-button-prev rounded-circle z-1 mx-3 border-0 bg-white">
<img src="{{ Vite::asset('resources/assets/images/common/arrow-brown.svg') }}"
title="{{ __('Navigation du slider (gauche)') }}"
alt="{{ __('flèche vers la gauche') }}">
title="{{ __('Navigation du slider (gauche)') }}" alt="{{ __('flèche vers la gauche') }}">
</button>
<button
class="swiper-button swiper-button-next-custom swiper-demarche-button-next rounded-circle z-1 mx-3 border-0 bg-white">
<img src="{{ Vite::asset('resources/assets/images/common/arrow-brown.svg') }}"
title="{{ __('Navigation du slider (droite)') }}"
alt="{{ __('flèche vers la droite') }}">
title="{{ __('Navigation du slider (droite)') }}" alt="{{ __('flèche vers la droite') }}">
</button>
</div>
</div>
@ -241,6 +232,7 @@
'models' => $recipeModels,
'btnRouteName' => route('fo.recipes.index'),
'btnRouteTitle' => 'recettes',
'hasPagination' => true,
])
@endif
{{-- NEWS --}}
@ -280,8 +272,7 @@
<div class="d-md-none">
@foreach ($newsModels->slice(1, 3) as $newsModel)
<li>
<a class="text-decoration-none"
href="{{ route('fo.news.show', $newsModel->slug) }}"
<a class="text-decoration-none" href="{{ route('fo.news.show', $newsModel->slug) }}"
title="{{ __('Voir l\'article :name', ['name' => $newsModel->title]) }}">
<p class="f-bakerie-rough mb-0">
{{ now()->subDays(rand(1, 31))->format('d/m/Y') }}</p>
@ -292,8 +283,7 @@
</div>
@foreach ($newsModels->slice(4, count($newsModels)) as $newsModel)
<li>
<a class="text-decoration-none"
href="{{ route('fo.news.show', $newsModel->slug) }}"
<a class="text-decoration-none" href="{{ route('fo.news.show', $newsModel->slug) }}"
title="{{ __('Voir l\'article :name', ['name' => $newsModel->title]) }}">
<p class="f-bakerie-rough mb-0">
{{ now()->subDays(rand(1, 31))->format('d/m/Y') }}</p>

View file

@ -8,12 +8,12 @@
{{-- HEADER --}}
@include('fo.layouts.header-banner')
{{-- MAIN CONTENT --}}
<section id="video-section" class="position-relative bg-light line-border-large overflow-hidden pt-5">
<section class="position-relative bg-light line-border-large overflow-hidden pt-5" id="video-section">
<div class="bg-white-wood-full">
<div class="container">
<div class="row mb-5 mt-4 align-items-center">
@include('fo.pages.news.toggleButton')
<div class="row mb-2 justify-content-center">
<div class="row align-items-center mb-5 mt-4">
{{-- @include('fo.pages.news.toggleButton') --}}
<div class="row justify-content-center mb-2">
<div class="col-12 col-md-10 col-lg-8 ck-content">
{!! clean($staticPageModel->content) !!}
</div>
@ -21,22 +21,22 @@
<div class="row">
@php
$data = [
'legendModels' => $newsCategories ?? [],
'legendImages' => false,
'legendField' => 'title',
'routeAjax' => 'fo.news.filtered',
'contentViews' => $newsViews,
'contentSwiper' => false,
'legendModels' => $newsCategories ?? [],
'legendImages' => false,
'legendField' => 'title',
'routeAjax' => 'fo.news.filtered',
'contentViews' => $newsViews,
'contentSwiper' => false,
'legendFakeFirst' => __('Toutes les actus'),
'texts' => [
'helperNoItems' => __('Aucune actualités disponibles dans cette catégorie'),
'texts' => [
'helperNoItems' => __('Aucune actualités disponibles dans cette catégorie'),
'helperAllItems' => __('Toutes les actualités ont été chargées'),
],
];
@endphp
<div class="filter-cards" data-json='@json($data)'></div>
<div class="filter-cards" data-json='@json($data)'></div>
</div>
</div>
</div>
</div>
</section>
@endsection

View file

@ -129,6 +129,24 @@
</div>
</div>
</section>
{{-- Video Modal --}}
<div class="modal fade translate-middle top-50 start-50" id="testimonial-video-modal" aria-labelledby="testimonialVideoModalLabel"
aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button class="btn-close" data-bs-dismiss="modal" type="button" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="video-inlaid ratio ratio-16x9" type="youtube"
href="https://www.youtube.com/embed/{{ $testimonialModels->first()->video_id }}"></div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal" type="button">{{ __('Fermer') }}</button>
</div>
</div>
</div>
</div>
@endif
{{-- ADVANTAGES --}}
<section class="joinus mb-3" id="recruitment-advantages">
@ -167,7 +185,7 @@
</section>
{{-- NEWS CORPORATE --}}
<section class="line-border-large bg-light py-5" id="recruitment-news-corporate">
<div class="container-fluid pt-lg-0 pt-5">
<div class="pt-lg-0 container pt-5">
<div class="row w-100 justify-content-center mx-auto">
<div class="col-12">
<h2 class="h1 f-intro-head-h-base text-center">
@ -183,7 +201,7 @@
id="swiper-recruitment-news-corporates">
<div class="swiper-wrapper">
@foreach ($newsCorporateModels as $newsCorporateModel)
<div class="swiper-slide">
<div class="swiper-slide h-auto">
@include('fo.partials.news-corporate-card', [
'newsCorporateModel' => $newsCorporateModel,
])

View file

@ -8,19 +8,20 @@
--}}
<div class="breeding-card bottom-left-shadow position-relative card mb-5 border-0 bg-transparent">
<div class="card-img-top line-border-medium img-wrapper bg-white p-2">
<img class="w-100 line-border-medium" src="{{ asset($picture['src']) }}" title="{{ $picture['alt'] }}" alt="{{ $picture['title'] }}">
</div>
<div class="card-body position-absolute w-100 d-flex flex-column p-0">
<div class="position-relative">
<div class="line-border-medium text-zone pb-4 pt-3">
<p class="text-uppercase fs-4 f-bourton-base px-4 pt-3 text-white">{{ $title }}</p>
</div>
<div class="position-absolute w-100 d-flex justify-content-center breeding-card-btn">
<a class="btn btn-quint f-bourton-base" href="{{ $link }}"
@if (!empty($linkNewTab)) target="_blank" @endif>{{ __('En savoir plus') }}</a>
<a href="{{ $link }}" @if (!empty($linkNewTab)) target="_blank" @endif>
<div class="card-img-top line-border-medium img-wrapper bg-white p-2">
<img class="w-100 line-border-medium" src="{{ asset($picture['src']) }}" title="{{ $picture['alt'] }}"
alt="{{ $picture['title'] }}">
</div>
<div class="card-body position-absolute w-100 d-flex flex-column p-0">
<div class="position-relative">
<div class="line-border-medium text-zone pb-4 pt-3">
<p class="text-uppercase fs-4 f-bourton-base px-4 pt-3 text-white">{{ $title }}</p>
</div>
<div class="position-absolute w-100 d-flex justify-content-center breeding-card-btn">
<div class="btn btn-quint f-bourton-base">{{ __('En savoir plus') }}</div>
</div>
</div>
</div>
</div>
</a>
</div>

View file

@ -1,12 +1,11 @@
<section id="commitments-banner-text-complex-items" class="position-relative w-100 py-5">
<div class="position-absolute top-50 start-0 translate-middle-y overflow-hidden w-100 h-100">
<img class="w-100" src="{{ Vite::asset($picture) }}"
alt="{{ $picture_alt }}" title="{{ $picture_title }}">
<section class="position-relative w-100 py-5" id="commitments-banner-text-complex-items">
<div class="responsive-position top-50 translate-middle-y w-100 h-100 start-0 overflow-hidden">
<img class="w-100" src="{{ Vite::asset($picture) }}" title="{{ $picture_title }}" alt="{{ $picture_alt }}">
</div>
<div class="container position-relative w-100 h-fit">
<div class="position-relative w-100 container h-fit">
<div class="row">
<div class="col-12 col-md-6">
<h2 class="text-white">{{ $title }}</h2>
<h2 class="banner-title">{{ $title }}</h2>
</div>
<div class="text-custom-placement col-12 col-md-6">
<hgroup class="line-border-small bg-white p-4">

View file

@ -1,11 +1,11 @@
<section id="commitments-complex-flex-items" class="position-relative">
<section class="position-relative" id="commitments-complex-flex-items">
@if (isset($title) && isset($picto))
<div class="position-absolute start-50 translate-middle w-100 px-5 z-1">
<div class="position-relative d-flex justify-content-center align-items-center w-fit mx-auto">
<img class="title-image position-absolute start-0 top-50 translate-middle img-fluid z-1"
src="{{ Vite::asset($picto) }}" alt="{{ $picto_alt }}" title="{{ $picto_title }}">
<div class="bg-tertiary line-border-small w-fit ps-5 p-3">
<h3 class="m-0">{{ $title }}</h3>
<div class="position-absolute start-50 translate-middle w-100 z-1 px-5">
<div class="position-relative d-flex justify-content-center align-items-center mx-auto w-fit">
<img class="title-image position-absolute top-50 translate-middle img-fluid z-1 start-0" src="{{ Vite::asset($picto) }}"
title="{{ $picto_title }}" alt="{{ $picto_alt }}">
<div class="bg-tertiary line-border-small w-fit p-3 ps-5">
<h3 class="m-0 text-center">{{ $title }}</h3>
@if (isset($subtitle))
<p class="f-bourton-base m-0">{{ $subtitle }}</p>
@endif
@ -14,15 +14,14 @@
</div>
@endif
<div class="line-border-large bg-{{ $background_color }} pb-5">
<div
class="container d-flex flex-column flex-md-row justify-content-center justify-content-evenly align-items-start pt-5 pb-4">
<div class="row justify-content-evenly align-items-start w-100 mx-auto mt-4 mt-lg-0">
<div class="d-flex flex-column flex-md-row justify-content-center justify-content-evenly align-items-start container pb-4 pt-5">
<div class="row justify-content-evenly align-items-start w-100 mt-lg-0 mx-auto mt-4">
@foreach ($collection as $item)
<div class="col-6 col-lg-4 card border-0 bg-transparent mb-3">
<div class="col-6 col-lg-4 card mb-3 border-0 bg-transparent">
<div class="row g-0">
<div class="col-12 d-flex justify-content-center align-items-center">
<img class="img-fluid" src="{{ Vite::asset($item->picto) }}"
alt="{{ $item->picto_alt }}" title="{{ $item->picto_title }}">
<img class="img-fluid" src="{{ Vite::asset($item->picto) }}" title="{{ $item->picto_title }}"
alt="{{ $item->picto_alt }}">
</div>
<div class="col-12">
<div class="card-body text-center">

View file

@ -46,7 +46,7 @@
'picto_alt' => __('Pictogramme d\'une plante'),
'picto_title' => __('Pousse d\'une plante au creux d\'une main'),
'title' => __('respecter la terre'),
'text' => __('être la grande marque alimentaire française'),
'text' => __('minimiser notre empreinte carbone et agir sur le changement climatique'),
'url' => route('fo.commitments.respect'),
],
];

View file

@ -53,7 +53,7 @@
<div class="swiper-slide">
@include('fo.partials.breeding-card', [
'picture' => [
'src' => $item->picture,
'src' => Vite::asset($item->picture),
'alt' => $item->picture_alt,
'title' => $item->picture_title,
],

View file

@ -30,8 +30,7 @@
])
@endif
@if (isset($btnLabel) && !empty($btnLabel))
<a href="{{ $btnLink }}" class="btn btn-{{ $btn_color }}"
title="{{ __('Accéder à la page') }}"
<a class="btn btn-{{ $btn_color }}" href="{{ $btnLink }}" title="{{ __('Accéder à la page') }}"
aria-label="{{ __('Accéder à la page') }}">{{ $btnLabel }}</a>
@endif
</div>
@ -45,11 +44,10 @@
'ratio ratio-16x9' => isset($video_id),
])>
@if (isset($picto) && !empty($picto))
<img @class([
<img src="{{ $picto }}" title="{{ $picto_title }}" alt="{{ $picto_alt }}" @class([
'img-fluid position-absolute z-1',
isset($reversed) && $reversed ? 'pictogram-reversed' : 'pictogram',
]) src="{{ $picto }}" alt="{{ $picto_alt }}"
title="{{ $picto_title }}">
])>
@endif
<div class="bottom-left-shadow">
<div @class([
@ -69,30 +67,37 @@
</a>
</div>
@endif
@if (isset($video_id) && \App\Rules\IsValidYoutubeId::validates($video_id))
<div class="video-inlaid w-100 h-100" type="youtube"
href="https://www.youtube.com/embed/{{ $video_id }}?autoplay=0&loop=1">
<a class="cn-cookie-link" id="youtube-warning" href="" rel="nofollow">
<strong class="text-underline text-bold text-normal text-danger">
{{ __('cookie-notice.custom.youtube.warning') }}
</strong>
</a>
</div>
@endif
<div class="position-relative w-100 h-fit">
@if (isset($video_id) && \App\Rules\IsValidYoutubeId::validates($video_id))
@if (isset($isVideoModal) && isset($video_id) && \App\Rules\IsValidYoutubeId::validates($video_id))
<div class="position-absolute z-1 w-100 h-100 start-0 top-0 bg-transparent" data-bs-toggle="modal"
data-bs-target="#mecenat-chirurgie-video-modal" role="button"></div>
@endif
<div class="video-inlaid w-100 h-100" type="youtube"
href="https://www.youtube.com/embed/{{ $video_id }}?autoplay=0&loop=1">
<a class="cn-cookie-link" id="youtube-warning" href="" rel="nofollow">
<strong class="text-underline text-bold text-normal text-danger">
{{ __('cookie-notice.custom.youtube.warning') }}
</strong>
</a>
</div>
@endif
</div>
@if (!isset($video_id))
<img class="img-fluid line-border-small w-100" src="{{ $picture }}"
alt="{{ $picture_alt }}" title="{{ $picture_title }}">
<img class="img-fluid line-border-small w-100" src="{{ $picture }}" title="{{ $picture_title }}"
alt="{{ $picture_alt }}">
@endif
</div>
</div>
@if (isset($card_title) && !empty($card_title))
<div class="custom-card bottom-left-shadow w-fit mx-auto mt-5 mt-md-0 z-1">
<img class="position-absolute z-2" src="{{ $card_picto }}" alt="{{ $card_picto_alt }}"
title="{{ $card_picto_title }}">
<p
class="position-absolute start-0 text-light bg-secondary rotate-left h6 m-0 p-2 ps-5 z-1">
<div class="custom-card bottom-left-shadow mt-md-0 z-1 mx-auto mt-5 w-fit">
<img class="position-absolute z-2" src="{{ $card_picto }}" title="{{ $card_picto_title }}"
alt="{{ $card_picto_alt }}">
<p class="position-absolute text-light bg-secondary rotate-left h6 z-1 start-0 m-0 p-2 ps-5">
{{ $card_sustitle }}</p>
<div class="bg-tertiary line-border-small text-center p-4">
<div class="bg-tertiary line-border-small p-4 text-center">
<h2>{{ $card_title }}</h2>
<p class="h6 m-0">{{ $card_subtitle }}</p>
<p class="m-0">{{ $card_text }}</p>

View file

@ -1,15 +1,17 @@
<section id="commitments-visual-with-cards" class="position-relative">
<section class="position-relative" id="commitments-visual-with-cards">
<div class="line-border-large bg-tertiary pb-5">
<div
class="container d-flex flex-column flex-md-row justify-content-center justify-content-evenly align-items-start pt-5 pb-4">
<div class="d-flex flex-column flex-md-row justify-content-center justify-content-evenly align-items-start container pb-4 pt-5">
<div class="row justify-content-evenly align-items-start gx-5">
<div class="col-12 mb-3">
<h2>{{ $title }}</h2>
</div>
<div class="col-12 col-md-5">
<div class="bottom-left-shadow mb-3">
<img class="line-border-small bg-white p-3 img-fluid" src="{{ Vite::asset($picture) }}"
alt="{{ $picture_alt }}" title="{{ $picture_title }}">
<div class="line-border-small bg-white p-2">
<img class="line-border-small img-fluid" src="{{ Vite::asset($picture) }}" title="{{ $picture_title }}"
alt="{{ $picture_alt }}">
</div>
</div>
<div class="bottom-left-shadow mb-3">
<div class="line-border-small bg-white p-3">
@ -18,20 +20,20 @@
</div>
</div>
<div class="col-12 col-md-7">
<div class="row w-100 mx-auto gx-5">
<div class="row w-100 gx-5 mx-auto">
<div class="col-12">
{!! $subtext !!}
</div>
<div class="col-12">
<div class="row w-100 mx-auto">
<div class="col-6">
<div class="col-12 col-md-6">
@foreach ($collection->slice(0, 2) as $item)
<div class="custom-card bottom-left-shadow position-relative my-4">
<div class="position-absolute d-flex justify-content-between align-items-center w-100 z-1">
<p class="h6 m-0 p-2 text-white bg-secondary rotate-left">
<p class="h6 bg-secondary rotate-left m-0 p-2 text-white">
{{ $item->title }}</p>
<img class="img-fluid" src="{{ Vite::asset($item->picto) }}"
alt="{{ $item->picto_alt }}" title="{{ $item->picto_title }}">
title="{{ $item->picto_title }}" alt="{{ $item->picto_alt }}">
</div>
<div class="line-border-small bg-white p-3 pt-5">
{!! $item->text !!}
@ -39,14 +41,14 @@
</div>
@endforeach
</div>
<div class="col-6">
<div class="col-12 col-md-6">
@foreach ($collection->slice(2, 2) as $item)
<div class="custom-card bottom-left-shadow position-relative my-4">
<div class="position-absolute d-flex justify-content-between align-items-center w-100 z-1">
<p class="h6 m-0 p-2 text-white bg-secondary rotate-left">
<p class="h6 bg-secondary rotate-left m-0 p-2 text-white">
{{ $item->title }}</p>
<img class="img-fluid" src="{{ Vite::asset($item->picto) }}"
alt="{{ $item->picto_alt }}" title="{{ $item->picto_title }}">
title="{{ $item->picto_title }}" alt="{{ $item->picto_alt }}">
</div>
<div class="line-border-small bg-white p-3 pt-5">
{!! $item->text !!}
@ -56,13 +58,13 @@
</div>
<div class="col-12">
<div class="custom-card bottom-left-shadow position-relative">
<div class="position-absolute w-fit z-1">
<p class="h6 m-0 p-2 text-white bg-secondary rotate-left">
<div class="position-absolute z-1 w-fit">
<p class="h6 bg-secondary rotate-left m-0 p-2 text-white">
{{ $collection->last()->title }}</p>
</div>
<div class="line-border-small bg-white d-flex justify-content-between align-items-center p-3">
<div class="line-border-small d-flex justify-content-between align-items-center bg-white p-3">
<img class="img-fluid" src="{{ Vite::asset($collection->last()->picto) }}"
alt="{{ $collection->last()->picto_alt }}" title="{{ $collection->last()->picto_title }}">
title="{{ $collection->last()->picto_title }}" alt="{{ $collection->last()->picto_alt }}">
<div class="ms-2">
{!! $collection->last()->text !!}
</div>

View file

@ -31,7 +31,7 @@
alt="{{ $hotNewsSettings->value['picture_alt'] }}"
title="{{ $hotNewsSettings->value['picture_title'] }}">
<div class="f-bourton-base bg-danger text-bg-danger px-2 py-1">
<span>@money($discountsTotal * 100)</span>
<span>@money($discountsTotal)</span>
{{ __(' d\'économie') }}
</div>
</div>

View file

@ -4,27 +4,28 @@
$newsCorporateModel || New corporate model. || Model || REQUIRED ||
--}}
<div class="news-card bottom-left-shadow card h-lg-100 border-0 bg-transparent w-100 w-lg-75 mx-0 mx-lg-auto mt-lg-0 mt-5">
<div class="line-border-small h-100 bg-white">
<div class="card-img-top position-relative mb-4">
<img class="w-100 line-border-small"
src="{{ asset($newsCorporateModel->picture) }}"
title="{{ $newsCorporateModel->picture_alt }}"
alt="{{ $newsCorporateModel->picture_title }}">
<div @class(['position-absolute tag rotate-left', 'd-none' => $newsCorporateModel->url ? false : true])>
<a href="{{ $newsCorporateModel->url ?? '#'}}"
title="{{ __('Accéder à l\'article sur Linkedin') }}"
target="_blank"
class="text-decoration-none text-uppercase text-bg-quad f-bourton-base fs-5 px-2 py-1">
{{ __('LINKEDIN') }}
</a>
<div class="news-card bottom-left-shadow card h-lg-100 w-100 mt-lg-0 mx-0 mt-5 border-0 bg-transparent">
<a class="text-decoration-none h-100" href="{{ $newsCorporateModel->url ?? '#' }}" title="{{ __('Accéder à l\'article sur Linkedin') }}"
target="_blank">
<div class="line-border-small h-100 bg-white">
<div class="card-img-top position-relative mb-4">
<img class="w-100 line-border-small" src="{{ asset($newsCorporateModel->picture) }}"
title="{{ $newsCorporateModel->picture_alt }}" alt="{{ $newsCorporateModel->picture_title }}">
<div @class([
'position-absolute tag rotate-left',
'd-none' => $newsCorporateModel->url ? false : true,
])>
<div class="text-decoration-none text-uppercase text-bg-quad f-bourton-base fs-5 px-2 py-1">
{{ __('LINKEDIN') }}
</div>
</div>
</div>
<div class="card-body p-4">
<h2 class="text-uppercase fs-4 f-bourton-base">
{{ $newsCorporateModel->title }}
</h2>
<p class="fs-5">{{ str($newsCorporateModel->content)->limit(300) }}</p>
</div>
</div>
<div class="card-body p-4">
<h2 class="text-uppercase fs-4 f-bourton-base">
{{ $newsCorporateModel->title }}
</h2>
<p class="fs-5">{{ $newsCorporateModel->content }}</p>
</div>
</div>
</a>
</div>

View file

@ -1,13 +1,13 @@
<div class="news-small-card bottom-left-shadow border-0 bg-transparent">
<a class="text-decoration-none" href="{{ $offerModel->link }}" target="_blank"
title="{{ __('Accéder à l\'offre : :name', ['name' => $offerModel->title]) }}">
<div class="line-border-small bg-white p-md-3">
<div class="row w-100 mx-auto align-items-center">
<div class="offer-small-card bottom-left-shadow h-100 border-0 bg-transparent">
<a class="text-decoration-none" href="{{ $offerModel->link }}"
title="{{ __('Accéder à l\'offre : :name', ['name' => $offerModel->title]) }}" target="_blank">
<div class="line-border-small p-md-3 h-100 d-flex flex-column bg-white">
<div class="row w-100 align-items-center mx-auto">
<div class="col-12 d-flex flex-column flex-md-row justify-content-center align-items-center p-0">
<img class="img-fluid" src="{{ $offerModel->picture }}" title="{{ $offerModel->picture_title }}"
alt="{{ $offerModel->picture_alt }}">
<div
class="d-flex flex-column justify-content-start justify-content-md-center align-items-start w-100 mb-2 mt-3 m-md-0 ms-md-2 px-3 px-md-0">
class="d-flex flex-column justify-content-start justify-content-md-center align-items-start w-100 m-md-0 ms-md-2 px-md-0 mb-2 mt-3 px-3">
<h4>{{ $offerModel->title }}</h4>
<p class="mb-0">
{{ Str::limit($offerModel->description, 180) }}
@ -17,14 +17,16 @@
</p>
</div>
</div>
<div class="col-12 d-flex flex-wrap p-3 pt-0 p-md-0 mt-md-1">
<div class="bg-quad text-uppercase f-bourton-base text-white fs-5 mt-2 me-3 px-2 py-1">
</div>
<div class="row w-100 align-items-center flex-fill mx-auto">
<div class="col-12 d-flex p-md-0 mt-md-1 align-items-center flex-wrap p-3 pt-0">
<div class="bg-quad text-uppercase f-bourton-base fs-5 me-3 mt-2 px-2 py-1 text-white">
{{ $offerModel->contract }}
</div>
<div class="bg-secondary text-uppercase f-bourton-base text-white fs-5 mt-2 me-3 px-2 py-1">
<div class="bg-secondary text-uppercase f-bourton-base fs-5 me-3 mt-2 px-2 py-1 text-white">
{{ $offerModel->location }}
</div>
<div class="bg-tertiary text-uppercase f-bourton-base fs-5 mt-2 me-3 px-2 py-1">
<div class="bg-tertiary text-uppercase f-bourton-base fs-5 me-3 mt-2 px-2 py-1">
{{ $offerModel->function }}
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="position-relative product-card bottom-left-shadow mt-3 py-3">
<div class="position-relative product-card bottom-left-shadow h-100 mt-5 py-3">
<div class="line-border-medium bg-tertiary position-absolute w-100 h-75 left-0 start-0"></div>
<div class="position-relative" title="{{ __('Accéder au produit : :name', ['name' => $model->label]) }}">
<div class="h-75 position-relative" title="{{ __('Accéder au produit : :name', ['name' => $model->label]) }}">
<a class="d-flex justify-content-center text-decoration-none pb-5" href="{{ route('fo.products.show', $model->slug) }}">
<img src="{{ asset($model->packaging) }}" title="{{ $model->packaging_title }}" alt="{{ $model->packaging_alt }}"
@class([
@ -23,10 +23,9 @@
</div>
{{-- BOTTOM PART --}}
<div class="position-relative">
<div class="line-border-medium position-relative d-flex flex-column align-items-center product-card-bottom-part bg-white pb-3">
<p class="text-uppercase f-bourton-base fs-4 my-4 px-4 text-center">
{{ $model->label }}
</p>
<div
class="line-border-medium position-relative d-flex flex-column align-items-center justify-content-center product-card-bottom-part bg-white pb-3">
<p class="text-uppercase f-bourton-base fs-4 my-4 px-4 text-center">{{ $model->label }}</p>
</div>
<div class="position-absolute w-100 d-flex justify-content-center bottom-0">
<a class="btn btn-secondary f-bourton-base product-card-view-more w-fit" href="{{ route('fo.products.show', $model->slug) }}"

View file

@ -1,49 +1,51 @@
<div class="recipe-card bottom-left-shadow h-100">
<div class="line-border-medium h-100 bg-white">
<div class="position-relative d-flex justify-content-center">
<a class="text-decoration-none" href="{{ route('fo.recipes.show', $model->slug) }}"
title="{{ __('Accéder à la recette : :title', ['title' => $model->title]) }}">
<a class="text-decoration-none" href="{{ route('fo.recipes.show', $model->slug) }}"
title="{{ __('Accéder à la recette : :title', ['title' => $model->title]) }}">
<div class="line-border-medium h-100 bg-white">
<div class="position-relative d-flex justify-content-center">
<img class="w-100 line-border-medium" src="{{ asset($model->picture) }}" title="{{ $model->picture_title }}"
alt="{{ $model->picture_alt }}" />
</a>
{{-- FIXME: change packaging by the first product packaging
{{-- FIXME: change packaging by the first product packaging
<img class="w-25 position-absolute recipe-card-product rotate-left z-1 bottom-0" src="{{ $model->products[0]->packaging }}"
title="{{ $model->products[0]->packaging_title }}" alt="{{ $model->products[0]->packaging_alt }}" /> --}}
<x-fo.btn-club-favorite :model="$model" />
</div>
<div class="recipe-card-bottom-part d-flex flex-column align-items-center px-3 pt-5">
<div style="min-height: 6.2rem; display: flex; align-items: center;">
<p class="text-uppercase fs-4 f-bourton-base text-center">
{{ $model->title }}
</p>
<x-fo.btn-club-favorite :model="$model" />
</div>
{{-- TIMES (COOKING & PREPARATION) & DIFFICULTY --}}
<div class="d-flex justify-content-around w-100">
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/clock.svg') }}"
title="{{ __('Icône du temps de préparation') }}" alt="{{ __('Horloge') }}" />
{{ $model->convertTime($model->preparation_time) }}
</p>
@if ($model->cooking_time)
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/cooking-pot.svg') }}"
title="{{ __('Icône du temps de cuisson') }}" alt="{{ __('Soupière') }}" />
{{ $model->convertTime($model->cooking_time) }}
<div class="recipe-card-bottom-part d-flex flex-column align-items-center px-3 pt-5">
<div style="min-height: 6.2rem; display: flex; align-items: center;">
<p class="text-uppercase fs-4 f-bourton-base text-center">
{{ $model->title }}
</p>
@endif
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/toque.svg') }}" title="{{ __('Icône de difficulté') }}"
alt="{{ __('Toque') }}" />
{{ $model->difficulty->label() }}
</p>
</div>
{{-- TIMES (COOKING & PREPARATION) & DIFFICULTY --}}
<div class="d-flex justify-content-around w-100">
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/clock.svg') }}"
title="{{ __('Icône du temps de préparation') }}" alt="{{ __('Horloge') }}" />
{{ $model->convertTime($model->preparation_time) }}
</p>
@if ($model->cooking_time)
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/cooking-pot.svg') }}"
title="{{ __('Icône du temps de cuisson') }}" alt="{{ __('Soupière') }}" />
{{ $model->convertTime($model->cooking_time) }}
</p>
@endif
<p class="text-uppercase fs-5 f-bourton-base">
<img src="{{ Vite::asset('resources/assets/images/recipes/toque.svg') }}" title="{{ __('Icône de difficulté') }}"
alt="{{ __('Toque') }}" />
{{ $model->difficulty->label() }}
</p>
</div>
{{-- SUBMEAT & CUNSUMPTION MOMENT --}}
@include('fo.partials.recipe-badges', [
'model' => $model,
'classWrapper' => 'recipe-card-badges-wrapper d-flex w-100 justify-content-center flex-wrap pb-3',
'class' =>
'badge recipe-tag text-bg-tertiary text-secondary text-uppercase f-catamaran fw-normal mx-md-3 mx-1 mb-2 px-3',
])
</div>
{{-- SUBMEAT & CUNSUMPTION MOMENT --}}
@include('fo.partials.recipe-badges', [
'model' => $model,
'classWrapper' => 'recipe-card-badges-wrapper d-flex w-100 justify-content-center flex-wrap pb-3',
'class' =>
'badge recipe-tag text-bg-tertiary text-secondary text-uppercase f-catamaran fw-normal mx-md-3 mx-1 mb-2 px-3',
])
</div>
</div>
</a>
</div>

View file

@ -1,12 +1,20 @@
<div class="testimonial-card bottom-left-shadow h-100 w-lg-75 ms-lg-auto">
<div class="position-relative d-flex justify-content-center testimonial-img-wrapper">
<div class="line-border-small w-fit bg-white p-2">
@if (!empty($model->video_id))
<a class="video-link" data-bs-toggle="modal" data-bs-target="#testimonial-video-modal"
data-video-link="https://www.youtube.com/embed/{{ $model->video_id }}">
<i class="fa-solid fa-xl fa-play position-absolute z-1 rounded-circle translate-middle top-50 start-50 bg-white p-3"></i>
@endif
<img class="w-100 line-border-medium testimonial-img" src="{{ asset($model->picture) }}" title="{{ $model->picture_title }}"
alt="{{ $model->picture_alt }}" />
@if (!empty($model->video_id))
</a>
@endif
</div>
</div>
<div
class="line-border-medium position-relative d-flex flex-column testimonial-card-bottom-part px-lg-5 px-lg-4 pb-lg-4 bg-light px-3 pt-4">
class="line-border-medium position-relative d-flex flex-column testimonial-card-bottom-part px-lg-5 px-lg-4 pb-lg-4 bg-light h-lg-100 px-3 pt-4">
<p class="text-uppercase fs-3 f-bourton-base mb-1">
{{ $model->identity }}
</p>

View file

@ -1,4 +1,4 @@
<script @if (isset($nonce)) nonce="{{ $nonce }}" @endif>
<script nonce="{{ $nonce ?? '' }}">
if (!window.__SYSTEM) {
window.__SYSTEM = {};
}

View file

@ -1,6 +1,6 @@
{{-- blade-formatter-disable --}}
@include('modules.script-constants')
<script @if (isset($nonce)) nonce="{{ $nonce }}" @endif>
<script nonce="{{ $nonce ?? '' }}">
if (!window.__SYSTEM._routes) {
window.__SYSTEM._routes = {};
}

View file

@ -76,7 +76,8 @@ Breadcrumbs::for('fo.recipes.search.submeat', function (Generator $trail) {
// * COMMITMENTS
Breadcrumbs::for('fo.commitments.index', function (Generator $trail) {
$trail->parent('fo.home.show');
$trail->push(Str::of(trans('nos engagements'))->ucfirst(), route('fo.commitments.index'));
// FIXME: Le lien ci-dessous doit etre .index après la MEP.
$trail->push(Str::of(trans('nos engagements'))->ucfirst(), route('fo.commitments.brand'));
});
Breadcrumbs::for('fo.commitments.brand', function (Generator $trail) {
$trail->parent('fo.commitments.index');

View file

@ -51,6 +51,9 @@ Route::middleware(['throttle:web', 'admin-secure'])->prefix('bo')->name('bo.')->
'verify' => false,
]
);
Route::get('/login-error', function () {
return view('bo.pages.login-error');
})->name('login-error');
});
Route::middleware('auth:backend')->group(function () {
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');