TIST-17: added single recipe page #15
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace Lycoreco\Apps\Recipes\Controllers;
|
namespace Lycoreco\Apps\Recipes\Controllers;
|
||||||
|
|
||||||
|
use Lycoreco\Apps\Recipes\Models\IngredientInRecipeModel;
|
||||||
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
||||||
|
use Lycoreco\Apps\Users\Models\UserModel;
|
||||||
use Lycoreco\Includes\BaseController;
|
use Lycoreco\Includes\BaseController;
|
||||||
use Lycoreco\Includes\Routing\HttpExceptions;
|
use Lycoreco\Includes\Routing\HttpExceptions;
|
||||||
|
|
||||||
@ -33,8 +35,26 @@ class SingleRecipeController extends BaseController
|
|||||||
public function get_context_data()
|
public function get_context_data()
|
||||||
{
|
{
|
||||||
$context = parent::get_context_data();
|
$context = parent::get_context_data();
|
||||||
|
$recipe = $this->get_model();
|
||||||
|
|
||||||
$context['recipe'] = $this->get_model();
|
|
||||||
|
$context['recipe'] = $recipe;
|
||||||
|
|
||||||
|
$context['author'] = UserModel::get(array(
|
||||||
|
[
|
||||||
|
'name' => 'obj.id',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => $recipe->field_author_id
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
$context['ingredients'] = IngredientInRecipeModel::filter(array(
|
||||||
|
[
|
||||||
|
'name' => 'obj.recipe_id',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => $recipe->get_id()
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
return $context;
|
return $context;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,4 +47,9 @@ class IngredientInRecipeModel extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->field_amount . ' ' . $this->ingredient_unit;
|
return $this->field_amount . ' ' . $this->ingredient_unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->ingredient_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -76,10 +76,20 @@ class RecipeModel extends BaseModel
|
|||||||
{
|
{
|
||||||
return ucfirst($this->field_status);
|
return ucfirst($this->field_status);
|
||||||
}
|
}
|
||||||
public function get_image_url() {
|
public function get_image_url()
|
||||||
|
{
|
||||||
if ($this->field_image_url)
|
if ($this->field_image_url)
|
||||||
return MEDIA_URL . $this->field_image_url;
|
return MEDIA_URL . $this->field_image_url;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_html_instruction(): string
|
||||||
|
{
|
||||||
|
return nl2br(trim($this->field_instruction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_time(){
|
||||||
|
return $this->field_estimated_time . " minutes";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ the_header(
|
|||||||
<i class="fa-solid fa-magnifying-glass search-icon"></i>
|
<i class="fa-solid fa-magnifying-glass search-icon"></i>
|
||||||
<input type="text" class="search-input" placeholder="Search categories...">
|
<input type="text" class="search-input" placeholder="Search categories...">
|
||||||
</div>
|
</div>
|
||||||
<!-- All labels and ids are the same for template design purposes (all labels point to same checkbox) -->
|
|
||||||
<div class="filters-checkboxes">
|
<div class="filters-checkboxes">
|
||||||
<ul>
|
<ul>
|
||||||
<?php foreach ($context['categories'] as $cat):
|
<?php foreach ($context['categories'] as $cat):
|
||||||
|
|||||||
@ -1,3 +1,133 @@
|
|||||||
<pre>
|
<?php
|
||||||
<?php var_dump($context['recipe']); ?>
|
require_once(INCLUDES_PATH . '/Const/recipes.php');
|
||||||
</pre>
|
the_header(
|
||||||
|
$context['recipe']->field_title,
|
||||||
|
'This is a single recipe page where you can view the details of the recipe, including ingredients, instructions, and more.',
|
||||||
|
'recipe',
|
||||||
|
[
|
||||||
|
|
||||||
|
['keywords', 'terms, use, conditions']
|
||||||
|
]
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="single-recipe">
|
||||||
|
<div class="single-recipe-info">
|
||||||
|
<div class="single-recipe-info__image">
|
||||||
|
<img src="<?= $context['recipe']->get_image_url(); ?>"
|
||||||
|
alt="<?php echo $context['recipe']->field_title; ?>">
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-info__details">
|
||||||
|
<div class="single-recipe-title">
|
||||||
|
<h1 class="title"><?php echo $context['recipe']->field_title; ?></h1>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data">
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Category: </span>
|
||||||
|
<span class="data"><?= $context['recipe']->category_name ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Author: </span>
|
||||||
|
<span class="data"><?= $context['author']->field_username ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Estimated Price: </span>
|
||||||
|
<span class="data"><?php echo $context['recipe']->get_price(); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Time To Make: </span>
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
|
|||||||
|
<span class="data"><?php echo $context['recipe']->get_time(); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Ingredients: </span>
|
||||||
|
<span class="data"><?= join(", ", $context['ingredients']) ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-data__item">
|
||||||
|
<span class="data-name">Date Created: </span>
|
||||||
|
<span class="data"><?php echo $context['recipe']->field_created_at; ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-ctrl">
|
||||||
|
<select class="hidden" name="daily-meal-select" id="daily-meal-day">
|
||||||
|
<?php foreach (DAYS_OF_WEEK as $day): ?>
|
||||||
|
<option value="<?= $day ?>"><?= ucfirst($day) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<option value="remove">Remove From List</option>
|
||||||
|
</select>
|
||||||
|
<div class="day-select-wrapper">
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
steve_dekart
commented
Days of the week can be used in different places, so it would be better to save them as a constant variable to make them reusable. You can create a new constant variable with all day of weeks in the format After that, include it using P.s. Only day of weeks. You don't need add to this array Days of the week can be used in different places, so it would be better to save them as a constant variable to make them reusable.
You can create a new constant variable with all day of weeks in the format `['monday' => 'Monday']`, and place it in the `Const/` directory as a file named `recipes.php` (create this directory inside `/includes/` if it doesn’t exist).
After that, include it using `require_once` and use a `foreach(DAY_OF_WEKS as $key => $label)` to generate the select options.
P.s. Only day of weeks. You don't need add to this array `remove`. It's not day of week. You can leave that option as it is.
steve_dekart
commented
Check TIST-27 Pull Request and approve it. After that, then I will merge it with develop, you can make In TIST-27 I have already added this const Check TIST-27 Pull Request and approve it. After that, then I will merge it with develop, you can make `git pull origin develop`.
In TIST-27 I have already added this const
|
|||||||
|
<div class="hover-anim">
|
||||||
|
<button type="button" href="#" id="day-select" class="btn btn-primary day-select">Add to
|
||||||
|
list</button>
|
||||||
|
<i class="fa-solid fa-list select-icon"></i>
|
||||||
|
</div>
|
||||||
|
<div id="custom-select-dropdown" class="custom-select-dropdown hidden">
|
||||||
|
<?php foreach (DAYS_OF_WEEK as $day): ?>
|
||||||
|
<div class="dropdown-item hover-anim" data-value="<?= $day?>">
|
||||||
|
<?= ucfirst($day) ?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<div class="dropdown-item hover-anim" data-value="remove">Remove From List</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="small-btns">
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
steve_dekart
commented
Same comment as above Same comment as above
|
|||||||
|
<button class="btn btn-secondary btn-small hover-anim" title="Add To Favorites">
|
||||||
|
<i class="fa-regular fa-heart"></i>
|
||||||
|
</button>
|
||||||
|
<a class="btn btn-secondary btn-small hover-anim"
|
||||||
|
href="<?php the_permalink('recipes:export-pdf', [$context['recipe']->get_id()]); ?>"
|
||||||
|
target="_blank" title="Export As PDF">
|
||||||
|
<i class="fa-solid fa-download"></i>
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-secondary btn-small hover-anim" id="qr-btn" title="Get QR Code">
|
||||||
|
<i class="fa-solid fa-qrcode"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="overlay" class="hidden"></div>
|
||||||
|
<div class="qr-popup hidden">
|
||||||
|
<div id="qrcode"></div>
|
||||||
|
<a id="downloadLink" class="btn btn-primary hover-anim" href="#" download="recipe-qr.png">
|
||||||
|
Download QR Code
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="single-recipe-content">
|
||||||
|
<div class="single-instructions">
|
||||||
|
<h2 class="title">Instructions</h2>
|
||||||
|
|
||||||
|
<?= $context['recipe']->get_html_instruction(); ?>
|
||||||
|
</div>
|
||||||
|
<div class="single-ingredients">
|
||||||
|
<h2 class="title">Ingredients</h2>
|
||||||
|
<table class="ingredients-table">
|
||||||
|
<thead>
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
steve_dekart
commented
You can create a new function like And it's really important You can create a new function like `get_html_instruction()` in the `RecipeModel`, which returns the formatted instruction (as string).
And it's really important `preg_replace('/(\d+\.\s)/', "\n$1", $context['recipe']->field_instruction)`? I think you can use only `nl2br(trim($formatted));`
|
|||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
foreach ($context['ingredients'] as $ing) {
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $ing; ?></td>
|
||||||
|
<td><?= $ing->get_count(); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php } ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<?php the_footer(array(
|
||||||
|
ASSETS_PATH . '/js/single.js',
|
||||||
|
)); ?>
|
||||||
@ -662,7 +662,6 @@ hr {
|
|||||||
|
|
||||||
label span {
|
label span {
|
||||||
color: #015847;
|
color: #015847;
|
||||||
/* Example: make the asterisk red */
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +675,7 @@ label span {
|
|||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background-color: var(--button-secondary);
|
background-color: var(--button-secondary);
|
||||||
height: 35px;
|
cursor: pointer;
|
||||||
max-width: 225px;
|
max-width: 225px;
|
||||||
color: var(--common-text);
|
color: var(--common-text);
|
||||||
}
|
}
|
||||||
@ -801,7 +800,6 @@ label span {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters-checkboxes ul li {
|
.filters-checkboxes ul li {
|
||||||
@ -813,6 +811,215 @@ label span {
|
|||||||
.filters-form .btn {
|
.filters-form .btn {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.single-recipe {
|
||||||
|
margin-top: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-title .title {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info__image {
|
||||||
|
width: 350px;
|
||||||
|
height: 260px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info__image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data__item {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data__item .data-name {
|
||||||
|
color: var(--meta-color);
|
||||||
|
margin-right: 10px;
|
||||||
|
flex: 0 0 120px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data__item .data {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.day-select {
|
||||||
|
position: relative;
|
||||||
|
width: 230px;
|
||||||
|
border: 1px solid #00775F;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-select-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-ctrl {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background-color: #008C71;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-small {
|
||||||
|
width: 35px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0;
|
||||||
|
border: 2px solid var(--input-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-ctrl {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.custom-select-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 110%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid var(--input-border);
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.custom-select-dropdown .dropdown-item:last-child {
|
||||||
|
border-top: 1px solid var(--input-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-selected {
|
||||||
|
background-color: #00775F;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-popup {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode img {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 9998;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-small,
|
||||||
|
.btn-small i {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-content h2 {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-content {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 30px;
|
||||||
|
gap: 40px;
|
||||||
|
/* flex-wrap: wrap; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-instructions{
|
||||||
|
width: 50%;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-ingredients{
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ingredients-table{
|
||||||
|
width: 400px;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #b3b3b3;
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ingredients-table th{
|
||||||
|
background-color: #008B70;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ingredients-table td{
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-top: 2px solid #b3b3b3;
|
||||||
|
}
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
||||||
.catalog-items {
|
.catalog-items {
|
||||||
@ -824,7 +1031,104 @@ label span {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.single-recipe-content {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.single-instructions,
|
||||||
|
.single-ingredients {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ingredients-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.single-recipe-info {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info__image {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 350px;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info__image img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-info__details {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-title .title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data__item {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-recipe-data__item .data-name {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
flex: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-ctrl {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-btns{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-select-wrapper,
|
||||||
|
.btn-small,
|
||||||
|
.btn-small i {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-small{
|
||||||
|
width: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-select-dropdown {
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
max-width: 230px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-popup {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
|
|
||||||
|
|
||||||
@ -904,22 +1208,26 @@ label span {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.catalog {
|
.catalog {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 46px;
|
margin-bottom: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
position: static;
|
position: static;
|
||||||
margin-bottom: 46px;
|
margin-bottom: 46px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-items {
|
.catalog-items {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.catalog-recipe {
|
.catalog-recipe {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -927,15 +1235,16 @@ label span {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
#food-3d {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 465px) {
|
@media (max-width: 465px) {
|
||||||
.catalog-recipe {
|
.catalog-recipe {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
|
||||||
}
|
}
|
||||||
#food-3d {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
@media (max-width: 400px) {
|
||||||
|
|||||||
71
assets/js/single.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
const toggleBtn = document.getElementById('day-select');
|
||||||
|
const dropdown = document.getElementById('custom-select-dropdown');
|
||||||
|
|
||||||
|
toggleBtn.addEventListener('click', () => {
|
||||||
|
dropdown.classList.toggle('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!dropdown.contains(e.target) && !toggleBtn.contains(e.target)) {
|
||||||
|
dropdown.classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const options = document.querySelectorAll('.dropdown-item');
|
||||||
|
|
||||||
|
options.forEach(option => {
|
||||||
|
option.addEventListener('click', () => {
|
||||||
|
const selectedValue = option.getAttribute('data-value');
|
||||||
|
|
||||||
|
options.forEach(opt => opt.classList.remove('dropdown-selected'));
|
||||||
|
|
||||||
|
if (selectedValue === 'remove') {
|
||||||
|
toggleBtn.textContent = 'Add to list';
|
||||||
|
} else {
|
||||||
|
toggleBtn.textContent = option.textContent;
|
||||||
|
option.classList.add('dropdown-selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
alert(`You selected: ${selectedValue}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const qrContainer = document.getElementById("qrcode");
|
||||||
|
const downloadLink = document.getElementById("downloadLink");
|
||||||
|
const qrBtn = document.getElementById("qr-btn");
|
||||||
|
const qrPopup = document.querySelector(".qr-popup");
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
steve_dekart
commented
This is not poppup, this is modal. Of course, you can leave it, but I think you need to create your own solution for modal. It's small difficulty, but after you can use this modal everywhere. So, every modal has same codebase: So default behavior for every modal you can implement in the This is not poppup, this is modal.
Of course, you can leave it, but I think you need to create your own solution for modal. It's small difficulty, but after you can use this modal everywhere.
So, every modal has same codebase:
```
<div id="overlay" class="hidden"></div>
<div class="qr-popup hidden"> <!-- it's not puppu, it's modal -->
<!-- Content -->
</div>
```
So default behavior for every modal you can implement in the `main.js`. After that, make some events for it. If you need more details, I can explain how to do it
steve_dekart
commented
We can talk about it on Discord We can talk about it on Discord
|
|||||||
|
const overlay = document.getElementById('overlay');
|
||||||
|
|
||||||
|
qrBtn.addEventListener("click", () => {
|
||||||
|
|
||||||
|
qrPopup.classList.toggle("hidden")
|
||||||
|
overlay.classList.toggle("hidden")
|
||||||
|
|
||||||
|
qrContainer.innerHTML = "";
|
||||||
|
|
||||||
|
|
||||||
|
new QRCode(qrContainer, {
|
||||||
|
text: window.location.href,
|
||||||
|
width: 200,
|
||||||
|
height: 200
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const qrImg = qrContainer.querySelector("img");
|
||||||
|
if (qrImg) {
|
||||||
|
downloadLink.href = qrImg.src;
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('click', (e) =>{
|
||||||
|
if(!qrPopup.contains(e.target) && !qrBtn.contains(e.target)){
|
||||||
|
qrPopup.classList.add("hidden");
|
||||||
|
overlay.classList.add("hidden");
|
||||||
|
}
|
||||||
|
});
|
||||||
1
assets/qrcode/qrcode.min.js
vendored
Normal file
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<script src="<?php echo ASSETS_PATH . '/js/main.js' ?>"></script>
|
<script src="<?php echo ASSETS_PATH . '/js/main.js' ?>"></script>
|
||||||
<script src="<?php echo ASSETS_PATH . '/toastify/toastify-js.js' ?>"></script>
|
<script src="<?php echo ASSETS_PATH . '/toastify/toastify-js.js' ?>"></script>
|
||||||
|
<script src="<?php echo ASSETS_PATH . '/qrcode/qrcode.min.js' ?>"></script>
|
||||||
|
greendavid004 marked this conversation as resolved
Outdated
steve_dekart
commented
I think you need to save this file in the ASSETS_PATH like I think you need to save this file in the ASSETS_PATH like `toastify.js`.
|
|||||||
<?php foreach($scripts as $script): ?>
|
<?php foreach($scripts as $script): ?>
|
||||||
<script src="<?php echo $script ?>"></script>
|
<script src="<?php echo $script ?>"></script>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|||||||
Can you create a new function in the RecipeModel that returns a string combining the estimated_time field and the word “minutes”? I think it will be used repeatedly in the future.