Recipe Pages UI updates (#776)

* Recipe updates

* Add help text icon
This commit is contained in:
Zack Arnett 2020-04-21 02:18:09 -04:00 committed by GitHub
parent f4b70e9ae3
commit 7fb76df33a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 160 additions and 92 deletions

View File

@ -1789,3 +1789,9 @@ msgstr ""
msgid "Show an icon if the product is already on the shopping list"
msgstr ""
msgid "Calories"
msgstr ""
msgid "By default the amount to be added to the shopping list is `needed amount - stock amount - shopping list amount` - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list"
msgstr ""

View File

@ -61,6 +61,7 @@ a.discrete-link:focus {
left: 0;
overflow: auto;
background-color: #ffffff;
width: 100%;
}
/* Fixes smooth scrolling on iOS */
@ -487,14 +488,34 @@ canvas.drawingBuffer {
flex-wrap: wrap;
}
.custom-control-label {
.form-control-lg .custom-control-label {
padding-top: 7px;
padding-left: 10px;
}
.custom-control-label {
padding-top: 13px;
padding-left: 10px;
}
.custom-control-label::before,
.custom-control-label::after {
top: 0.8rem;
width: 1.25rem;
height: 1.25rem;
}
.recipe-card-name {
font-size: 16px;
text-align: center;
width: 100%;
}
.recipe-expand {
right: 1.25rem;
top: .75rem;
}
.recipe-servings-input {
width: 125px;
}

View File

@ -326,13 +326,21 @@ $('#save-recipe-include-button').on('click', function(e)
}
});
$("#recipe-picture").on("change", function (e) {
$("#recipe-picture-label").removeClass("d-none");
$("#recipe-picture-label-none").addClass("d-none");
$("#delete-current-recipe-picture-on-save-hint").addClass("d-none");
$("#current-recipe-picture").addClass("d-none");
Grocy.DeleteRecipePictureOnSave = false;
});
Grocy.DeleteRecipePictureOnSave = false;
$('#delete-current-recipe-picture-button').on('click', function (e)
{
Grocy.DeleteRecipePictureOnSave = true;
$("#current-recipe-picture").addClass("d-none");
$("#delete-current-recipe-picture-on-save-hint").removeClass("d-none");
$("#delete-current-recipe-picture-button").addClass("disabled");
$("#delete-current-recipe-picture-button").on("click", function (e) {
Grocy.DeleteRecipePictureOnSave = true;
$("#current-recipe-picture").addClass("d-none");
$("#delete-current-recipe-picture-on-save-hint").removeClass("d-none");
$("#recipe-picture-label").addClass("d-none");
$("#recipe-picture-label-none").removeClass("d-none");
});
Grocy.Components.UserfieldsForm.Load();

View File

@ -17,7 +17,9 @@
@php if(!isset($noNameAttribute)) { $noNameAttribute = false; } @endphp
<div class="form-group {{ $additionalGroupCssClasses }}">
<label for="{{ $id }}">{{ $__t($label) }}&nbsp;&nbsp;<span id="{{ $hintId }}" class="small text-muted">{{ $hint }}</span>{!! $additionalHtmlContextHelp !!}</label>
<label for="{{ $id }}">
{{ $__t($label) }}&nbsp;
<i class="fas fa-question-circle" id="{{ $hintId }}" data-toggle="tooltip" title="{{ $hint }}"></i>{!! $additionalHtmlContextHelp !!}</label>
<div class="input-group">
<input {!! $additionalAttributes !!} type="number" class="form-control numberpicker {{ $additionalCssClasses }}" id="{{ $id }}" @if(!$noNameAttribute) name="{{ $id }}" @endif value="{{ $value }}" min="{{ $min }}" max="{{ $max }}" step="{{ $step }}" @if($isRequired) required @endif>
<div class="input-group-append">

View File

@ -13,7 +13,11 @@
@php if(empty($nextInputSelector)) { $nextInputSelector = ''; } @endphp
<div class="form-group" data-next-input-selector="{{ $nextInputSelector }}" data-disallow-add-product-workflows="{{ BoolToString($disallowAddProductWorkflows) }}" data-disallow-all-product-workflows="{{ BoolToString($disallowAllProductWorkflows) }}" data-prefill-by-name="{{ $prefillByName }}" data-prefill-by-id="{{ $prefillById }}">
<label for="product_id">{{ $__t($label) }} <i class="fas fa-barcode"></i><span id="barcode-lookup-disabled-hint" class="small text-muted d-none"> {{ $__t('Barcode lookup is disabled') }}</span>&nbsp;&nbsp;<span class="small text-muted">{{ $hint }}</span></label>
<label for="product_id">
{{ $__t($label) }}&nbsp;<i class="fas fa-barcode"></i>&nbsp;
<span id="barcode-lookup-disabled-hint" class="small text-muted d-none"> {{ $__t('Barcode lookup is disabled') }}</span>&nbsp;
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $hint }}"></i>
</label>
<select class="form-control product-combobox barcodescanner-input" id="product_id" name="product_id" @if($isRequired) required @endif @if($disabled) disabled @endif data-target="@productpicker">
<option value=""></option>
@foreach($products as $product)

View File

@ -47,11 +47,26 @@
<input type="text" class="form-control" required id="name" name="name" value="@if($mode == 'edit'){{ $recipe->name }}@endif">
<div class="invalid-feedback">{{ $__t('A name is required') }}</div>
</div>
<div class="form-group">
<label for="description">{{ $__t('Preparation') }}</label>
<textarea id="description" class="form-control wysiwyg-editor" name="description">@if($mode == 'edit'){{ $recipe->description }}@endif</textarea>
</div>
<label for="recipe-picture">
{{ $__t('Picture') }}
</label>
<div class="input-group">
<div class="custom-file">
<input type="file" class="custom-file-input" id="recipe-picture" accept="image/*">
<label id="recipe-picture-label" class="custom-file-label @if(empty($recipe->picture_file_name)) d-none @endif" for="recipe-picture">
{{ $recipe->picture_file_name }}
</label>
<label id="recipe-picture-label-none" class="custom-file-label @if(!empty($recipe->picture_file_name)) d-none @endif" for="recipe-picture">
{{ $__t('No file selected') }}
</label>
</div>
<div class="input-group-append">
<span class="input-group-text"><i class="fas fa-trash" id="delete-current-recipe-picture-button"></i></span>
</div>
</div>
</div>
@php if($mode == 'edit') { $value = $recipe->base_servings; } else { $value = 1; } @endphp
@include('components.numberpicker', array(
@ -64,25 +79,19 @@
))
<div class="form-group">
<div class="form-check">
<div class="custom-control custom-checkbox">
<input type="hidden" name="not_check_shoppinglist" value="0">
<input @if($mode == 'edit' && $recipe->not_check_shoppinglist == 1) checked @endif class="form-check-input" type="checkbox" id="not_check_shoppinglist" name="not_check_shoppinglist" value="1">
<label class="form-check-label" for="not_check_shoppinglist">{{ $__t('Do not check against the shopping list when adding missing items to it') }}&nbsp;&nbsp;
<span class="small text-muted">{{ $__t('By default the amount to be added to the shopping list is "needed amount - stock amount - shopping list amount" - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list') }}</span>
<input @if($mode == 'edit' && $recipe->not_check_shoppinglist == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="not_check_shoppinglist" name="not_check_shoppinglist" value="1">
<label class="form-check-label custom-control-label" for="not_check_shoppinglist">
{{ $__t('Do not check against the shopping list when adding missing items to it') }}&nbsp;
<i class="fas fa-question-circle"
data-toggle="tooltip"
title="{{ $__t('By default the amount to be added to the shopping list is `needed amount - stock amount - shopping list amount` - when this is enabled, it is only checked against the stock amount, not against what is already on the shopping list') }}"
></i>
</label>
</div>
</div>
<div class="form-group">
<label for="recipe-picture">{{ $__t('Picture') }}
<span class="text-muted small">{{ $__t('If you don\'t select a file, the current picture will not be altered') }}</span>
</label>
<div class="custom-file">
<input type="file" class="custom-file-input" id="recipe-picture" accept="image/*">
<label class="custom-file-label" for="recipe-picture">{{ $__t('No file selected') }}</label>
</div>
</div>
@include('components.productpicker', array(
'products' => $products,
'isRequired' => false,
@ -96,7 +105,12 @@
'entity' => 'recipes'
))
<button id="save-recipe-button" class="btn btn-success">{{ $__t('Save') }}</button>
<div class="form-group">
<label for="description">{{ $__t('Preparation') }}</label>
<textarea id="description" class="form-control wysiwyg-editor" name="description">@if($mode == 'edit'){{ $recipe->description }}@endif</textarea>
</div>
<button id="save-recipe-button" class="btn btn-success mb-2">{{ $__t('Save') }}</button>
</form>
</div>
@ -104,12 +118,27 @@
<div class="col-xs-12 col-md-5 pb-3">
<div class="row">
<div class="col">
<h2>
{{ $__t('Ingredients list') }}
<a id="recipe-pos-add-button" class="btn btn-outline-dark recipe-pos-add-button" type="button" href="#">
<i class="fas fa-plus"></i> {{ $__t('Add') }}
</a>
</h2>
@if(!empty($recipe->picture_file_name))
<img id="current-recipe-picture" data-src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}" class="img-fluid img-thumbnail mt-2 lazy mb-5">
<p id="delete-current-recipe-picture-on-save-hint" class="form-text text-muted font-italic d-none mb-5">{{ $__t('The current picture will be deleted when you save the recipe') }}</p>
@else
<p id="no-current-recipe-picture-hint" class="form-text text-muted font-italic mb-5">{{ $__t('No picture available') }}</p>
@endif
</div>
</div>
<div class="row">
<div class="col">
<div class="title-related-links">
<h4>
{{ $__t('Ingredients list') }}
</h4>
<div class="related-links">
<a id="recipe-pos-add-button" class="btn btn-outline-primary btn-sm recipe-pos-add-button" type="button" href="#">
{{ $__t('Add') }}
</a>
</div>
</div>
<table id="recipes-pos-table" class="table table-sm table-striped dt-responsive">
<thead>
@ -176,12 +205,16 @@
<div class="row mt-5">
<div class="col">
<h2>
{{ $__t('Included recipes') }}
<a id="recipe-include-add-button" class="btn btn-outline-dark" href="#">
<i class="fas fa-plus"></i> {{ $__t('Add') }}
</a>
</h2>
<div class="title-related-links">
<h4>
{{ $__t('Included recipes') }}
</h4>
<div class="related-links">
<a id="recipe-include-add-button" class="btn btn-outline-primary btn-sm" href="#">
{{ $__t('Add') }}
</a>
</div>
</div>
<table id="recipes-includes-table" class="table table-sm table-striped dt-responsive">
<thead>
<tr>
@ -215,19 +248,6 @@
</table>
</div>
</div>
<div class="row mt-5">
<div class="col">
<label class="mt-2">{{ $__t('Picture') }}</label>
<button id="delete-current-recipe-picture-button" class="btn btn-sm btn-danger @if(empty($recipe->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>
@if(!empty($recipe->picture_file_name))
<p><img id="current-recipe-picture" data-src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}" class="img-fluid img-thumbnail mt-2 lazy"></p>
<p id="delete-current-recipe-picture-on-save-hint" class="form-text text-muted font-italic d-none">{{ $__t('The current picture will be deleted when you save the recipe') }}</p>
@else
<p id="no-current-recipe-picture-hint" class="form-text text-muted font-italic">{{ $__t('No picture available') }}</p>
@endif
</div>
</div>
</div>
</div>

View File

@ -143,28 +143,52 @@
@if($selectedRecipe !== null)
<div class="col-xs-12 col-md-6">
<div id="selectedRecipeCard" class="card">
<div class="card-header card-header-fullscreen">
<i class="fas fa-cocktail"></i> {{ $selectedRecipe->name }}&nbsp;&nbsp;
<a id="selectedRecipeConsumeButton" class="btn btn-sm btn-outline-success py-0 hide-when-embedded hide-on-fullscreen-card @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->need_fulfilled == 0) disabled @endif" href="#" data-toggle="tooltip" title="{{ $__t('Consume all ingredients needed by this recipe') }}" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-utensils"></i>
</a>
<a class="btn btn-sm btn-outline-primary py-0 recipe-order-missing-button hide-when-embedded hide-on-fullscreen-card @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif" href="#" data-toggle="tooltip" title="{{ $__t('Put missing products on shopping list') }}" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-cart-plus"></i>
</a>&nbsp;&nbsp;
<a id="selectedRecipeEditButton" class="btn btn-sm btn-outline-info hide-when-embedded hide-on-fullscreen-card py-0" href="{{ $U('/recipe/') }}{{ $selectedRecipe->id }}">
<i class="fas fa-edit"></i>
</a>
<a id="selectedRecipeDeleteButton" class="btn btn-sm btn-outline-danger hide-when-embedded hide-on-fullscreen-card py-0" href="#" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-trash"></i>
</a>
<a id="selectedRecipeToggleFullscreenButton" class="btn btn-sm btn-outline-secondary py-0 hide-when-embedded float-right" href="#" data-toggle="tooltip" title="{{ $__t('Expand to fullscreen') }}">
<i class="fas fa-expand-arrows-alt"></i>
</a>
<div class="card-header card-header-fullscreen position-relative">
<div class="position-absolute">
<a id="selectedRecipeEditButton" class="btn btn-sm btn-outline-info hide-when-embedded hide-on-fullscreen-card py-0" href="{{ $U('/recipe/') }}{{ $selectedRecipe->id }}">
<i class="fas fa-edit"></i>
</a>
<a id="selectedRecipeDeleteButton" class="btn btn-sm btn-outline-danger hide-when-embedded hide-on-fullscreen-card py-0 mr-2" href="#" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-trash"></i>
</a>
<a id="selectedRecipeConsumeButton" class="btn btn-sm btn-outline-success py-0 hide-when-embedded hide-on-fullscreen-card @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->need_fulfilled == 0) disabled @endif" href="#" data-toggle="tooltip" title="{{ $__t('Consume all ingredients needed by this recipe') }}" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-utensils"></i>
</a>
<a class="btn btn-sm btn-outline-primary py-0 recipe-order-missing-button hide-when-embedded hide-on-fullscreen-card @if(FindObjectInArrayByPropertyValue($recipesResolved, 'recipe_id', $selectedRecipe->id)->need_fulfilled_with_shopping_list == 1) disabled @endif" href="#" data-toggle="tooltip" title="{{ $__t('Put missing products on shopping list') }}" data-recipe-id="{{ $selectedRecipe->id }}" data-recipe-name="{{ $selectedRecipe->name }}">
<i class="fas fa-cart-plus"></i>
</a>
</div>
<div class="recipe-card-name">{{ $selectedRecipe->name }}</div>
<div class="recipe-expand position-absolute">
<a id="selectedRecipeToggleFullscreenButton" class="btn btn-sm btn-outline-secondary py-0 hide-when-embedded" href="#" data-toggle="tooltip" title="{{ $__t('Expand to fullscreen') }}">
<i class="fas fa-expand-arrows-alt"></i>
</a>
</div>
</div>
<div class="card-body mb-0 pb-0">
<div class="row">
@if(!empty($selectedRecipeTotalCalories) && intval($selectedRecipeTotalCalories) > 0)
<div class="col-2">
<label>{{ $__t('Calories') }}</label>
<p class="mb-0">
<h3 class="locale-number locale-number-generic pt-0">{{ $selectedRecipeTotalCalories }}</h3>
</p>
</div>
@endif
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
<div class="col-6">
<label>{{ $__t('Costs') }}&nbsp;</label>
<i class="fas fa-question-circle" data-toggle="tooltip" title="{{ $__t('Based on the prices of the last purchase per product') }}"></i>
<p class="mb-0">
<h3 class="locale-number locale-number-currency pt-0">{{ $selectedRecipeTotalCosts }}</h3>
</p>
</div>
@endif
</div>
<div class="row py-3">
<div class="col-4">
@include('components.numberpicker', array(
'id' => 'servings-scale',
@ -176,24 +200,6 @@
'hint' => $__t('Base: %s', $selectedRecipe->base_servings)
))
</div>
@if(!empty($selectedRecipeTotalCalories) && intval($selectedRecipeTotalCalories) > 0)
<div class="col-2">
<label>{{ $__t('Energy (kcal)') }}</label>
<p class="mb-0">
<h3 class="locale-number locale-number-generic pt-0">{{ $selectedRecipeTotalCalories }}</h3>
</p>
</div>
@endif
@if(GROCY_FEATURE_FLAG_STOCK_PRICE_TRACKING)
<div class="col-6">
<label>{{ $__t('Costs') }}&nbsp;&nbsp;
<span class="small text-muted">{{ $__t('Based on the prices of the last purchase per product') }}</span>
</label>
<p class="mb-0">
<h3 class="locale-number locale-number-currency pt-0">{{ $selectedRecipeTotalCosts }}</h3>
</p>
</div>
@endif
</div>
<!-- Subrecipes first -->
@ -265,12 +271,13 @@
<!-- Selected recipe -->
@if(!empty($selectedRecipe->picture_file_name))
<p class="w-75 mx-auto text-center"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}" class="img-fluid img-thumbnail lazy"></p>
<img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name) . '?force_serve_as=picture&best_fit_width=400') }}"
class="img-thumbnail lazy mx-auto d-block mb-5">
@endif
@if($selectedRecipePositionsResolved->count() > 0)
<h5 class="mb-0">{{ $__t('Ingredients') }}</h5>
<ul class="list-group list-group-flush">
<h4 class="mb-2">{{ $__t('Ingredients') }}</h4>
<ul class="list-group list-group-flush mb-5">
@php
$lastIngredientGroup = 'undefined';
$lastProductGroup = 'undefined';
@ -321,7 +328,7 @@
@endif
@if(!empty($selectedRecipe->description))
<h5 class="mt-4">{{ $__t('Preparation') }}</h5>
<h4 class="mt-1 mb-2">{{ $__t('Preparation') }}</h4>
{!! $selectedRecipe->description !!}
@endif
</div>