recipes.index page

This commit is contained in:
Jérémy Munsch 2021-02-09 09:50:17 +01:00
parent 086f38d50d
commit 44b4e0aab9
19 changed files with 813 additions and 19 deletions

View file

@ -3,24 +3,24 @@
namespace App\Enums;
/**
* @method static self video()
* @method static self classic()
* @method static self video()
*/
final class RecipeType extends BaseEnum
{
protected static function values(): array
{
return [
'video' => 0,
'classic' => 1
'classic' => 0,
'video' => 1
];
}
protected static function labels(): array
{
return [
'video' => __('Video'),
'classic' => __('Classic'),
'video' => __('Video')
];
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace App\Facades;
use App\Enums\RecipeType as EnumsRecipeType;
use Illuminate\Support\Facades\Facade;
class RecipeType extends Facade
{
protected static function getFacadeAccessor()
{
return EnumsRecipeType::class;
}
}

View file

@ -0,0 +1,115 @@
<?php
namespace App\Http\Controllers;
use App\Enums\RecipeType;
use App\Models\ConsumptionTimes;
use App\Models\Ranges;
use App\Models\Recipes;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class RecipesController extends Controller
{
public function index(Request $request)
{
$type = $request->get('type');
$value = $request->get('value');
$search = $request->get('search');
$video_recipe = $request->get('video_recipe');
// @phpcs:disable PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
if (
!session()->has('recipes.rand') ||
(intval(session()->get('recipes.time', time())) - intval(time())) > (60 * 60 * 60) // 1 hour
) {
session()->put('recipes.time', time());
session()->put('recipes.rand', Recipes::all('id')->shuffle()->map(function ($obj) {
return $obj->id;
})->toArray());
session()->save();
}
$recipes = Recipes::select('title', 'slug', 'picture', 'catch_phrase')
->where('status', true)
->orderByRaw(\sprintf('FIELD(id, %s)', implode(", ", session()->get('recipes.rand'))));
if ($search) {
$recipes = $recipes->where('title', 'like', '%' . implode('%', explode(' ', trim($search))) . '%');
}
if ($video_recipe) {
$recipes = $recipes->where('type', '=', RecipeType::video()->value);
}
$ranges = Ranges::select('name', 'slug')
->where('status', true)
->orderBy('order')
->get();
$consumptionTimes = ConsumptionTimes::select('name', 'slug')
->where('status', true)
->get();
try {
switch ($type) {
case 'range':
$recipes = $recipes->whereHas('products.range', function ($q) use ($value) {
$q->where('ranges.slug', $value);
});
break;
case 'consumption':
$recipes = $recipes->whereHas('consumptionTimes', function ($q) use ($value) {
$q->where('consumption_times.slug', $value);
});
break;
case 'preparation':
switch ($value) {
case 'less15':
$recipes = $recipes->where('preparation_time', '<=', 15);
break;
case '15and30':
$recipes = $recipes
->where('preparation_time', '>=', 15)
->where('preparation_time', '<=', 30);
break;
default:
case 'more30':
$recipes = $recipes
->where('preparation_time', '>', 30);
break;
}
break;
case 'cooking':
switch ($value) {
case 'less15':
$recipes = $recipes->where('cooking_time', '<=', 15);
break;
case '15and30':
$recipes = $recipes
->where('cooking_time', '>=', 15)
->where('cooking_time', '<=', 30);
break;
default:
case 'more30':
$recipes = $recipes
->where('cooking_time', '>', 30);
break;
}
break;
}
} catch (ModelNotFoundException $e) {
}
$recipes = $recipes->paginate();
return view('front.recipes.index', compact(
'recipes',
'ranges',
'consumptionTimes',
'type',
'value'
));
}
}

View file

@ -72,7 +72,7 @@ class Products extends Model
public function recipes()
{
return $this->belongsToMany(Recipes::class);
return $this->belongsToMany(Recipes::class, 'recipes_products', 'recipe_id', 'product_id');
}
//TODO: PSR1 is not in camel caps format

View file

@ -17,7 +17,7 @@ class Ranges extends Model
public function products()
{
return $this->hasMany(Products::class);
return $this->hasMany(Products::class, 'range_id');
}
public function reductions()

View file

@ -27,7 +27,7 @@ class Recipes extends Model
public function products()
{
return $this->hasMany(Products::class);
return $this->belongsToMany(Products::class, 'recipes_products', 'product_id', 'recipe_id');
}
public function product1()
@ -44,4 +44,9 @@ class Recipes extends Model
{
return $this->belongsToMany(Customers::class);
}
public function consumptionTimes()
{
return $this->belongsTo(ConsumptionTimes::class);
}
}

View file

@ -236,6 +236,7 @@ return [
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'RecipeType' => \App\Facades\RecipeType::class
],
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 KiB

View file

@ -1,6 +1,27 @@
// Body
$body-bg: #f8fafc;
// Breaking Points
$large_screen : 1366px;
$big_screen : 1200px;
$desktop : 1024px;
$tablet : 768px;
$mobile : 500px;
$xmobile : 320px;
$minLscreen : only screen and (min-width: $large_screen);
$minBscreen : only screen and (min-width: $big_screen);
$minDesktop : only screen and (min-width: $desktop);
$minTablet : only screen and (min-width: $tablet);
$minMobile : only screen and (min-width: $mobile);
$minxMobile : only screen and (min-width: $xmobile);
$max499 : only screen and (max-width: 499px);
$max767 : only screen and (max-width: 767px);
$max1023 : only screen and (max-width: 1023px);
$max1199 : only screen and (max-width: 1199px);
$max1365 : only screen and (max-width: 1365px);
// Typography
$font-family-sans-serif: 'Nunito', sans-serif;
$font-size-base: 0.9rem;
@ -23,3 +44,16 @@ $theme-colors: (
"primary": #3176C4,
"secondary": #E7374B
);
$color10: #999595;
$color11: #ab9d8e;
$color9: #c6bcb3;
$color1: #f3ebe4;
$color2: #07386a;
$color3: #0f437e;
$color4: #1e5ba1;
$color5: #4e3238;
$color6: #f79e15;
$color8: #ffb504;
$color7: #e02125;
$orange: #ffb400;

26
resources/sass/front/_pagination.scss vendored Normal file
View file

@ -0,0 +1,26 @@
.pagination {
display: block;
text-align: center;
margin: 2em 0;
li {
display: inline-block;
&.active span {
color: $color6;
text-decoration: underline;
}
a,span {
display: block;
font-size: 1.5em;
padding: 0.5em;
margin: 0.5em;
background-color: $color3;
color: $color1;
font-weight: bold;
border-radius: 1px;
border-color: $color8;
}
}
}

View file

@ -378,6 +378,215 @@
}
}
.sub_header_recipes {
background-image: url(../images/recette/recette_background.jpg);
width: 100%;
height: 38em;
margin-top: 6em;
overflow: hidden;
background-size: cover;
background-position: center center;
& .title {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
margin: 20em 0 0;
width: 100%;
z-index: 1;
& h1 {
color: white;
text-align: center;
font-size: 7em;
font-family: 'Veneer';
}
}
.search-field {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
margin: 31em 0 0;
width: 70em;
z-index: 1;
.search{
width:80%;
svg {
position: absolute;
left: 0.4em;
top: 0.6em;
font-size: 2.6em;
color: #999595;
}
}
input {
border: none;
float: left;
}
input[type="text"] {
color: #999595;
width: 18em;
height: 2em;
font-family: "CreamyScriptRegular";
font-size: 2.8em;
border-radius: 0.1em;
padding: 0 0.1em 0 2em;
}
input[type="submit"] {
background: $color5;
color: #fff;
cursor: pointer;
font-size: 1.5em;
font-family: 'Catamaran-Black';
margin-left: 1.4em;
width: 11em;
height: 3.6em;
border-radius: 0.2em;
text-transform: uppercase;
}
.checkbox-wrap {
float: right;
margin: 1em 21em 0 0;
display: flex;
align-items: center;
position: relative;
& > label {
font-family: "CreamyScriptRegular";
font-size: 3em;
color: #fff;
cursor: pointer;
&.label_video {
display: inline-block;
}
}
input[type="checkbox"]:not(:checked),
input[type="checkbox"]:checked {
/* Cache la checkbox sans
la rendre invisible aux
lecteurs d'écran */
position: absolute;
left: 0;
opacity: 0.01;
}
input[type="checkbox"] + label {
position: relative; /* permet de positionner la checkbox */
padding-left: 2.3em; /* place pour la box */
font-size: 1.05em;
line-height: 1.7;
cursor: pointer;
display: block;
font-family: "CreamyScriptRegular";
color: #fff;
top: -1em;
right: -1em;
&:before {
content: '';
display: inline-block;
position: absolute;
left: 0;
top: 0;
height: 2em;
width: 2em;
background-color: #fff;
border-color: #e5dace;
border-radius: 0.2em;
border-style: solid;
border-width: 0.2em;
}
&:after {
position: absolute;
border-left: 0;
border-top: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #e5dace;
content: "\e902";
font-family: 'icomoon';
font-size: 0.8em;
left: 0.5em;
top: 0.5em;
display:none;
}
}
input[type="checkbox"]:checked + label {
&:before {
border: #4e3238;
background: #4e3238;
}
&:after {
display:block;
}
}
}
}
.wrap-btn-right {
position: absolute;
right: 10%;
top: 235px;
display:block;
.btn_cplm {
background-color: rgba(255,255,255,0.5);
color: $color5;
display: block;
width: 7em;
height: 2.2em;
font-family: "CreamyScriptRegular";
font-size: 3em;
line-height: 0.8em;
margin-bottom: 0.5em;
border-radius: 0.2em;
padding: 0.2em 0 0 2.2em;
position: relative;
span {
font-family: 'Veneer';
font-size: 1em;
display: block;
}
&.propose_recipe {
&:before {
content: "\e932";
color: $color5;
font-family: 'icomoon' !important;
font-size: 1.3em;
position: absolute;
left: 0.35em;
top: 50%;
margin-top: -0.4em;
}
}
&.favorite_recipe {
&:before {
content: "\e909";
color: $color5;
font-family: 'icomoon' !important;
font-size: 1em;
position: absolute;
left: 0.5em;
top: 50%;
margin-top: -0.4em;
}
}
}
}
}
}
.sub_header_ocb {
width: 100%;
height: 370px;

216
resources/sass/front/pages/_recipes.scss vendored Normal file
View file

@ -0,0 +1,216 @@
.content.recipes {
max-width:100%;
margin: 0 auto;
& .recipeList{
max-width: $big_screen;
margin-top: 50px;
margin-left: auto;
margin-right: auto;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
.recipeWrapper {
text-align: center;
max-width:371px;
margin-top:25px;
margin-bottom:25px;
figure {
height: 236px;
margin: 8px 8px 27px;
border: 8px solid white;
padding: 0;
position: relative;
display:flex;
align-items: center;
justify-content: center;
overflow: hidden;
.hoverFigure{
position:absolute;
top:0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(247, 158, 21, 0.7);
z-index:5;
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity 500ms ease 0s;
&:hover{
opacity: 1;
}
h5{
color:#FFFFFF;
font-size:4em;
position: relative;
&:before {
background-image: url(../images/recette/hoverRecette.png);
display: inline-block;
content: "";
width: 100px;
height: 35px;
position: absolute;
top: -40px;
left: 50%;
transform: translateX(-50%);
}
&:after {
background-image: url(../images/recette/hoverRecette.png);
display: inline-block;
content: "";
width: 100px;
height: 35px;
transform: rotate(180deg) translateX(54%);
position: absolute;
top: 45px;
left: 50%;
}
}
}
img {
background: $color5;
min-height:100%;
min-width: 100%;
width:100%;
height:auto;
}
}
p {
font-family: 'Catamaran-Bold';
font-size: 18px;
padding: 0 40px;
text-transform: uppercase;
&:last-child {
color: $color6;
font-family: "CreamyScriptRegular";
font-size: 26px;
text-transform: none;
text-shadow: 1px 0 0 #4e3238, -1px 0 0 #4e3238, 0 1px 0 #4e3238, 0 -1px 0 #4e3238, 1px 1px #4e3238, -1px -1px 0 #4e3238, 1px -1px 0 #4e3238, -1px 1px 0 #4e3238;
}
}
}
h3 {
text-align: center;
margin-bottom: 2em;
}
}
& .recipes-filter {
span {
cursor: pointer;
}
ul.recipeFilterMenu {
background-color: $color6;
position: relative;
z-index: 15;
margin: 0 auto;
display: block !important;
& > li {
float: left;
width: 25%;
margin: 0 auto;
text-align: center;
border-right: 1px solid #fed67f;
&:hover {
.ssmenu {
display: block;
}
a,i {
color: $color5;
}
}
&.active {
& > a, & > span {
color: white;
}
}
& > a, & > span {
text-align: center;
}
.ssmenu {
display: none;
position: absolute;
width: 25%;
padding: 18px 0 21px 44px;
display: none;
z-index: 999;
background-color: #ffffff;
box-shadow: 0px 5px 5px 0px #444444;
a {
display: block;
text-align: left;
padding: 0;
color: $color5;
&:hover {
color: $color6;
}
}
li.active {
a {
color: $color6;
}
}
}
}
a, label, span {
font-family: 'CreamyScriptRegular';
color: #ffffff;
&:hover {
color: $color5;
}
}
a, span {
text-align: left;
display: block;
font-size: 3em;
height:100%;
display: flex;
justify-content: center;
align-items: center;
padding: 30px 0;
text-align: left;
& > h5 {
color:#FFFFFF;
font-size:1em;
}
&:hover {
color: $color5;
h5{
color: $color5;
}
i {
color: $color5;
}
}
& > svg {
display: inline-block;
padding-left: 10px;
}
}
& > label {
display: inline-block;
max-width: 100%;
margin-right: 21px;
font-family: 'CreamyScriptRegular';
color: #ffffff;
font-size: 3em;
}
}
}
}

View file

@ -1,11 +1,14 @@
@import "~normalize.css/normalize.css";
@import "~@fortawesome/fontawesome-free/css/all.min.css";
@import "variables";
@import "front/reset";
@import "front/fonts";
@import "front/body";
@import "front/header";
@import "front/sub_header";
@import "front/footer";
@import "front/pagination";
.pattern {
background-repeat: repeat;
@ -63,11 +66,7 @@
@import "front/pages/home";
@import "front/pages/products";
@import "front/pages/product";
@import "front/pages/legals";
@import "front/pages/traceability";
@import "front/pages/quality";
@import "front/pages/recipes";
@import "front/pages/ocb/index";
@import "front/pages/ocb/breeder";

View file

@ -0,0 +1,3 @@
<svg aria-hidden="true" focusable="false" data-prefix="fa" data-icon="chevron-down" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg="" class="svg-inline--fa fa-chevron-down fa-w-14">
<path fill="currentColor" d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"></path>
</svg>

After

Width:  |  Height:  |  Size: 546 B

View file

@ -0,0 +1,3 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="search" class="svg-inline--fa fa-search fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"></path>
</svg>

After

Width:  |  Height:  |  Size: 584 B

View file

@ -0,0 +1,66 @@
@extends('layouts.app')
@section('title', __('Toutes les recettes'))
@section('description', __('Envie de préparer des plats gourmands avec de la volaille 100% française ? Le Gaulois a la
solution avec ses recettes faciles et originales'))
@section('sub_header')
<div class="sub_header_recipes">
<div class="title">
<h1 class="pattern">{{ __('Les Recettes') }}</h1>
</div>
<form action="{{ request()->url() }}">
<div class="search-field">
<div class="search">
<input type="text" name="search" placeholder="{{ __('Rechercher une recette') }}" value="{{ request()->query('search') }}">
@include('front.icons.search')
</div>
<input type="submit" value="{{ __('Rechercher') }}">
<div class="checkbox-wrap">
<label for="video_recipe" class="label_video">{{ __('Recette en vidéo') }}</label>
<div class="check">
<input type="checkbox" class="videobox magic-checkbox" name="video_recipe" id="video_recipe" @if(request()->query('video_recipe'))checked @endif>
<label for="video_recipe"></label>
</div>
</div>
</div>
</form>
<div class="wrap-btn-right">
<a href="{{ route('recipes.propose') }}" class="btn_cplm propose_recipe" title="{{ __('Proposer une recette') }}">{{ __('Proposer') }}&nbsp;<span>{{ __('Une recette') }}</span></a>
{{-- TODO: mettre condition ici si user connected --}}
{{-- IF CUSTOMER CONNECTED --}}
<a href="{{ route('customer.favRecipes') }}" class="btn_cplm favorite_recipe" title="{{ __('Recettes favorites') }}">{{ __('Recettes') }}&nbsp;<span>{{ __('Favorites') }}</span></a>
{{-- ELSE --}}
<a href="#connexion-modal" class="btn_cplm favorite_recipe" title="{{ __('Recettes favorites') }}">{{ __('Recettes') }}&nbsp;<span>{{ __('Favorites') }}</span></a>
{{-- ENDIF --}}
</div>
</div>
@endsection
@section('content')
<div class="content recipes">
@include('front.recipes.recipes-filter')
{{ $recipes->withQueryString()->links() }}
<div class="recipeList">
@if(count($recipes))
@foreach($recipes as $recipe)
<div class="recipeWrapper">
<a href="{{ route('recipes.show', $recipe->slug) }}">
<figure>
<div class="hoverFigure">
<h5>{{ __('Voir la recette !') }}</h5>
</div>
<img src="{{ asset($recipe->picture) }}" alt="{{ $recipe->title }}">
</figure>
<p class="name_recette">{{ $recipe->title }}</p>
<p>{{ $recipe->catch_phrase }}</p>
</a>
</div>
@endforeach
@else
<h3>{{ __('Aucun résultat') }}</h3>
@endif
</div>
{{ $recipes->withQueryString()->links() }}
</div>
@endsection

View file

@ -0,0 +1,102 @@
<nav class="recipes-filter">
<ul class="recipeFilterMenu clearfix">
@if(count($ranges))
<li>
<span class="recipeMenuItem">
<h5>{{ __('Gammes') }}</h5>
@include('front.icons.chevron-down')
</span>
<div class="ssmenu">
<ul>
@foreach($ranges as $range)
<li @if($type=='range' && $value==$range->slug )class="active" @endif>
<a title="{{ $range->name }}" href="{{ route('recipes.index', [
'type' => 'range',
'value' => $range->slug
]) }}">{{ $range->name }}</a>
</li>
@endforeach
</ul>
</div>
</li>
@endif
@if(count($consumptionTimes))
<li>
<span class="recipeMenuItem">
<h5>{{ __('Moment de Consommation') }}</h5>
@include('front.icons.chevron-down')
</span>
<div class="ssmenu">
<ul>
@foreach ($consumptionTimes as $consumptionTime)
<li @if($type=='consumption' && $value==$consumptionTime->slug )class="active" @endif>
<a title="{{ $consumptionTime->name }}" href="{{ route('recipes.index', [
'type' => 'consumption',
'value' => $consumptionTime->slug
]) }}">{{ $consumptionTime->name }}</a>
</li>
@endforeach
</ul>
</div>
</li>
@endif
<li>
<span class="recipeMenuItem">
<h5>{{ __('Temps de Préparation') }}</h5>
@include('front.icons.chevron-down')
</span>
<div class="ssmenu">
<ul>
<li @if($type=='preparation' && $value=='less15' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'preparation',
'value' => 'less15'
]) }}">{{ __('Moins de 15min') }}</a>
</li>
<li @if($type=='preparation' && $value=='15and30' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'preparation',
'value' => '15and30'
]) }}">{{ __('De 15 à 30min') }}</a>
</li>
<li @if($type=='preparation' && $value=='more30' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'preparation',
'value' => 'more30'
]) }}">{{ __('Plus de 30min') }}</a>
</li>
</ul>
</div>
</li>
<li>
<span class="recipeMenuItem">
<h5>{{ __('Temps de Cuisson') }}</h5>
@include('front.icons.chevron-down')
</span>
<div class="ssmenu">
<ul>
<li @if($type=='cooking' && $value=='less15' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'cooking',
'value' => 'less15'
]) }}">{{ __('Moins de 15min') }}</a>
</li>
<li @if($type=='cooking' && $value=='15and30' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'cooking',
'value' => '15and30'
]) }}">{{ __('De 15 à 30min') }}</a>
</li>
<li @if($type=='cooking' && $value=='more30' )class="active" @endif>
<a href="{{ route('recipes.index', [
'type' => 'cooking',
'value' => 'more30'
]) }}">{{ __('Plus de 30min') }}</a>
</li>
</ul>
</div>
</li>
</ul>
</nav>

View file

@ -21,7 +21,7 @@
<ul class="rightside">
<li>
<i class="fa fa-chevron-right" aria-hidden="true"></i>
<a href="{{ route('recipes') }}">Les recettes</a>
<a href="{{ route('recipes.index') }}">Les recettes</a>
</li>
<li>
<i class="fa fa-chevron-right" aria-hidden="true"></i>

View file

@ -162,13 +162,14 @@ Route::prefix('/cote-cuisine')
});
Route::get('/recettes', function (){
die('Recettes');
})->name('recipes');
Route::get('/recettes', 'RecipesController@index')->name('recipes.index');
Route::get('/proposer-une-recette', function () {
dd('proposer recette');
})->name('recipes.propose');
Route::get('/recette/{slug}', function($slug) {
die("Recette " . $slug);
})->name('recipe');
Route::get('/recettes-favorites', function () {
dd('proposer recette');
})->name('customer.favRecipes');
Route::prefix('/la-marque')
->name('brand.')