mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-07 07:08:03 -05:00
Merge branch 'develop' into add-human-friendly-css-classes
This commit is contained in:
@@ -11,50 +11,90 @@
|
||||
<b-button variant="primary" v-b-tooltip.hover :title="$t('Create')" @click="createNew">
|
||||
<i class="fas fa-plus"></i>
|
||||
</b-button>
|
||||
<b-dropdown variant="primary" id="sortDropDown" text="Order By" class="border-left">
|
||||
<b-dropdown-item @click = "orderBy('id','asc')" :disabled= "isActiveSort('id','asc')">oldest to newest</b-dropdown-item>
|
||||
<b-dropdown-item @click = "orderBy('id','desc')" :disabled= "isActiveSort('id','desc')">newest to oldest</b-dropdown-item>
|
||||
<b-dropdown-item @click = "orderBy('name','asc')" :disabled= "isActiveSort('name','asc')">alphabetical order</b-dropdown-item>
|
||||
<b-dropdown-item @click = "orderBy('order','asc')" :disabled= "isActiveSort('order','asc')" >manually</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</b-input-group-append>
|
||||
<b-button class= "ml-2" variant="primary" v-if="isActiveSort('order','asc')" @click="handleEditButton" >
|
||||
{{submitText}}
|
||||
</b-button>
|
||||
</b-input-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-bottom: 55px">
|
||||
<div class="mb-3" v-for="book in filteredBooks" :key="book.id">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<b-card class="d-flex flex-column" v-hover v-on:click="openBook(book.id)">
|
||||
<b-row no-gutters style="height: inherit">
|
||||
<b-col no-gutters md="10" style="height: inherit">
|
||||
<b-card-body class="m-0 py-0" style="height: inherit">
|
||||
<b-card-text class="h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
|
||||
<h5 class="m-0 mt-1 text-truncate">
|
||||
{{ book.name }} <span class="float-right"><i class="fa fa-book"></i></span>
|
||||
</h5>
|
||||
<div class="m-0 text-truncate">{{ book.description }}</div>
|
||||
<div class="mt-auto mb-1 d-flex flex-row justify-content-end"></div>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-card>
|
||||
<div v-if="!isActiveSort('order','asc') || !manSubmitted">
|
||||
<div style="padding-bottom: 55px">
|
||||
<div class="mb-3" v-for="(book) in filteredBooks" :key="book.id">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<b-card class="d-flex flex-column" v-hover >
|
||||
<b-row no-gutters style="height: inherit" class="d-flex align-items-center">
|
||||
<b-col no-gutters style="height: inherit">
|
||||
<b-card-body class="m-0 py-0" style="height: inherit">
|
||||
<b-card-text class="h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
|
||||
<b-button v-on:click="openBook(book.id)" style="color: #000; background-color: white" variant="primary">
|
||||
<h5 class="m-0 mt-1 text-truncate" >
|
||||
{{ book.name }} <span class="float-right"><i class="fa fa-book"></i></span>
|
||||
</h5></b-button>
|
||||
<div class="m-0 text-truncate">{{ book.description }}</div>
|
||||
<div class="mt-auto mb-1 d-flex flex-row justify-content-end"></div>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<loading-spinner v-if="current_book === book.id && loading"></loading-spinner>
|
||||
<transition name="slide-fade">
|
||||
<cookbook-slider
|
||||
:recipes="recipes"
|
||||
:book="book"
|
||||
:key="`slider_${book.id}`"
|
||||
v-if="current_book === book.id && !loading"
|
||||
v-on:refresh="refreshData"
|
||||
@reload="openBook(current_book, true)"
|
||||
></cookbook-slider>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<loading-spinner v-if="current_book === book.id && loading"></loading-spinner>
|
||||
<transition name="slide-fade">
|
||||
<cookbook-slider
|
||||
:recipes="recipes"
|
||||
:book="book"
|
||||
:key="`slider_${book.id}`"
|
||||
v-if="current_book === book.id && !loading"
|
||||
v-on:refresh="refreshData"
|
||||
@reload="openBook(current_book, true)"
|
||||
></cookbook-slider>
|
||||
</transition>
|
||||
|
||||
</div>
|
||||
<div v-else>
|
||||
<draggable
|
||||
@change="updateManualSorting"
|
||||
:list="cookbooks" ghost-class="ghost">
|
||||
<b-card no-body class="mt-1 list-group-item p-2"
|
||||
style="cursor: move"
|
||||
v-for=" (book,index) in filteredBooks"
|
||||
v-hover
|
||||
:key="book.id">
|
||||
<b-card-header class="p-2 border-0">
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<button type="button"
|
||||
class="btn btn-lg shadow-none"><i
|
||||
class="fas fa-arrows-alt-v"></i></button>
|
||||
</div>
|
||||
<div class="col-10">
|
||||
<h5 class="mt-1 mb-1">
|
||||
<b-badge class="float-left text-white mr-2">
|
||||
#{{ index + 1 }}
|
||||
</b-badge>
|
||||
{{ book.name }}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</b-card-header>
|
||||
</b-card>
|
||||
</draggable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<bottom-navigation-bar active-view="view_books">
|
||||
<template #custom_create_functions>
|
||||
@@ -72,7 +112,7 @@
|
||||
<script>
|
||||
import Vue from "vue"
|
||||
import { BootstrapVue } from "bootstrap-vue"
|
||||
|
||||
import draggable from "vuedraggable"
|
||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||
import { ApiApiFactory } from "@/utils/openapi/api"
|
||||
import CookbookSlider from "@/components/CookbookSlider"
|
||||
@@ -85,7 +125,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: "CookbookView",
|
||||
mixins: [ApiMixin],
|
||||
components: { LoadingSpinner, CookbookSlider, BottomNavigationBar },
|
||||
components: { LoadingSpinner, CookbookSlider, BottomNavigationBar, draggable },
|
||||
data() {
|
||||
return {
|
||||
cookbooks: [],
|
||||
@@ -94,6 +134,11 @@ export default {
|
||||
current_book: undefined,
|
||||
loading: false,
|
||||
search: "",
|
||||
activeSortField : 'id',
|
||||
activeSortDirection: 'desc',
|
||||
inputValue: "",
|
||||
manSubmitted : false,
|
||||
submitText: "Edit"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -110,7 +155,7 @@ export default {
|
||||
methods: {
|
||||
refreshData: function () {
|
||||
let apiClient = new ApiApiFactory()
|
||||
|
||||
|
||||
apiClient.listRecipeBooks().then((result) => {
|
||||
this.cookbooks = result.data
|
||||
})
|
||||
@@ -168,7 +213,45 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
orderBy: function(order_field,order_direction){
|
||||
let apiClient = new ApiApiFactory()
|
||||
const options = {
|
||||
order_field: order_field,
|
||||
order_direction: order_direction
|
||||
}
|
||||
this.activeSortField = order_field
|
||||
this.activeSortDirection = order_direction
|
||||
apiClient.listRecipeBooks(options).then((result) => {
|
||||
this.cookbooks = result.data
|
||||
})
|
||||
},
|
||||
isActiveSort: function(field, direction) {
|
||||
// Check if the current item is the active sorting option
|
||||
return this.activeSortField === field && this.activeSortDirection === direction;
|
||||
},
|
||||
handleEditButton: function(){
|
||||
if (!this.manSubmitted){
|
||||
this.submitText = "Back"
|
||||
this.manSubmitted = true
|
||||
} else {
|
||||
this.submitText = "Edit"
|
||||
this.manSubmitted = false
|
||||
}
|
||||
},
|
||||
updateManualSorting: function(){
|
||||
let old_order = Object.assign({}, this.cookbooks);
|
||||
let promises = []
|
||||
this.cookbooks.forEach((element, index) => {
|
||||
let apiClient = new ApiApiFactory()
|
||||
promises.push(apiClient.partialUpdateManualOrderBooks(element.id, {order: index}))
|
||||
})
|
||||
return Promise.all(promises).then(() => {
|
||||
}).catch((err) => {
|
||||
this.cookbooks = old_order
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||
})
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
hover: {
|
||||
inserted: function (el) {
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
<div class="flex-grow-1 ml-2"
|
||||
style="text-overflow: ellipsis; overflow-wrap: anywhere;">
|
||||
<span class="two-row-text">
|
||||
<a :href="resolveDjangoUrl('view_recipe', plan.entry.recipe.id)" v-if="plan.entry.recipe">{{ plan.entry.recipe.name }}</a>
|
||||
<a :href="getRecipeURL(plan.entry.recipe, plan.entry.servings)" v-if="plan.entry.recipe">{{ plan.entry.recipe.name }}</a>
|
||||
<span v-else>{{ plan.entry.title }}</span> <br/>
|
||||
</span>
|
||||
<span v-if="plan.entry.note" class="two-row-text">
|
||||
@@ -169,7 +169,7 @@
|
||||
v-if="contextData && contextData.originalItem && contextData.originalItem.entry.recipe != null"
|
||||
@click="
|
||||
$refs.menu.close()
|
||||
openRecipe(contextData.originalItem.entry.recipe)
|
||||
openRecipe(contextData.originalItem.entry.recipe, contextData.originalItem.entry.servings)
|
||||
"
|
||||
>
|
||||
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-pizza-slice"></i>
|
||||
@@ -392,8 +392,13 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openRecipe: function (recipe) {
|
||||
window.open(this.resolveDjangoUrl("view_recipe", recipe.id))
|
||||
|
||||
getRecipeURL: function (recipe, servings) {
|
||||
return this.resolveDjangoUrl("view_recipe",`${recipe.id}?servings=${servings}`)
|
||||
},
|
||||
|
||||
openRecipe: function (recipe, servings) {
|
||||
window.open(this.getRecipeURL(recipe, servings))
|
||||
},
|
||||
setStartingDay(days) {
|
||||
if (this.settings.startingDayOfWeek + days < 0) {
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
@change="uploadImage($event.target.files[0])"/>
|
||||
|
||||
<div
|
||||
class="h-100 w-100 border border-primary rounded"
|
||||
style="border-width: 2px !important; border-style: dashed !important"
|
||||
@drop.prevent="uploadImage($event.dataTransfer.files[0])"
|
||||
@dragover.prevent
|
||||
@click="$refs.file_upload.click()"
|
||||
class="h-100 w-100 border border-primary rounded"
|
||||
style="border-width: 2px !important; border-style: dashed !important"
|
||||
@drop.prevent="uploadImage($event.dataTransfer.files[0])"
|
||||
@dragover.prevent
|
||||
@click="$refs.file_upload.click()"
|
||||
>
|
||||
<i class="far fa-image fa-10x text-primary"
|
||||
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
||||
@@ -71,27 +71,27 @@
|
||||
<br/>
|
||||
<label for="id_name"> {{ $t("Keywords") }}</label>
|
||||
<multiselect
|
||||
v-model="recipe.keywords"
|
||||
:options="keywords"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="true"
|
||||
:hide-selected="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_keyword')"
|
||||
:tag-placeholder="$t('add_keyword')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addKeyword"
|
||||
label="label"
|
||||
track-by="id"
|
||||
id="id_keywords"
|
||||
:multiple="true"
|
||||
:loading="keywords_loading"
|
||||
@search-change="searchKeywords"
|
||||
v-model="recipe.keywords"
|
||||
:options="keywords"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="true"
|
||||
:hide-selected="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_keyword')"
|
||||
:tag-placeholder="$t('add_keyword')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addKeyword"
|
||||
label="label"
|
||||
track-by="id"
|
||||
id="id_keywords"
|
||||
:multiple="true"
|
||||
:loading="keywords_loading"
|
||||
@search-change="searchKeywords"
|
||||
>
|
||||
<template v-slot:noOptions>{{ $t("empty_list") }}</template>
|
||||
</multiselect>
|
||||
@@ -103,21 +103,21 @@
|
||||
<div class="col-md-12">
|
||||
<div class="card mt-2 mb-2">
|
||||
<div class="card-body pr-2 pl-2 pr-md-5 pl-md-5 pt-3 pb-3">
|
||||
<h6>{{ $t('Properties') }} <small class="text-muted"> {{$t('per_serving')}}</small></h6>
|
||||
<h6>{{ $t('Properties') }} <small class="text-muted"> {{ $t('per_serving') }}</small></h6>
|
||||
|
||||
<div class="alert alert-info" role="alert">
|
||||
{{ $t('recipe_property_info')}}
|
||||
{{ $t('recipe_property_info') }}
|
||||
</div>
|
||||
|
||||
<div class="d-flex mt-2" v-for="p in recipe.properties" v-bind:key="p.id">
|
||||
<div class="flex-fill w-50">
|
||||
<generic-multiselect
|
||||
@change="p.property_type = $event.val"
|
||||
:initial_single_selection="p.property_type"
|
||||
:label="'name'"
|
||||
:model="Models.PROPERTY_TYPE"
|
||||
:limit="25"
|
||||
:multiple="false"
|
||||
@change="p.property_type = $event.val"
|
||||
:initial_single_selection="p.property_type"
|
||||
:label="'name'"
|
||||
:model="Models.PROPERTY_TYPE"
|
||||
:limit="25"
|
||||
:multiple="false"
|
||||
></generic-multiselect>
|
||||
</div>
|
||||
<div class="flex-fill w-50">
|
||||
@@ -190,14 +190,14 @@
|
||||
<br/>
|
||||
<label> {{ $t("Share") }}</label>
|
||||
<generic-multiselect
|
||||
@change="recipe.shared = $event.val"
|
||||
parent_variable="recipe.shared"
|
||||
:initial_selection="recipe.shared"
|
||||
:label="'display_name'"
|
||||
:model="Models.USER_NAME"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
v-bind:placeholder="$t('Share')"
|
||||
:limit="25"
|
||||
@change="recipe.shared = $event.val"
|
||||
parent_variable="recipe.shared"
|
||||
:initial_selection="recipe.shared"
|
||||
:label="'display_name'"
|
||||
:model="Models.USER_NAME"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
v-bind:placeholder="$t('Share')"
|
||||
:limit="25"
|
||||
></generic-multiselect>
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
|
||||
<button class="dropdown-item" @click="removeStep(step)"><i
|
||||
class="fa fa-trash fa-fw"></i> {{ $t("Delete") }}
|
||||
class="fa fa-trash fa-fw"></i> {{ $t("Delete") }}
|
||||
</button>
|
||||
|
||||
<button class="dropdown-item" @click="moveStep(step, step_index - 1)"
|
||||
@@ -249,7 +249,7 @@
|
||||
<button class="dropdown-item" @click="setStepShowIngredientsTable(step, true)"
|
||||
v-if="! step.show_ingredients_table">
|
||||
<i class="op-icon fa fa-mavon-eye"></i> {{ $t("show_step_ingredients") }}
|
||||
</button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -300,11 +300,11 @@
|
||||
<i class="fas fa-plus-circle"></i> {{ $t("File") }}
|
||||
</b-button>
|
||||
<b-button
|
||||
pill
|
||||
variant="primary"
|
||||
size="sm"
|
||||
class="ml-1 mb-1 mb-md-0"
|
||||
@click="
|
||||
pill
|
||||
variant="primary"
|
||||
size="sm"
|
||||
class="ml-1 mb-1 mb-md-0"
|
||||
@click="
|
||||
paste_step = step
|
||||
$bvModal.show('id_modal_paste_ingredients')
|
||||
"
|
||||
@@ -327,31 +327,31 @@
|
||||
<label :for="'id_step_' + step.id + '_file'">{{ $t("File") }}</label>
|
||||
<b-input-group>
|
||||
<multiselect
|
||||
ref="file"
|
||||
v-model="step.file"
|
||||
:options="files"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:placeholder="$t('select_file')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:id="'id_step_' + step.id + '_file'"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="files_loading"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
@search-change="searchFiles"
|
||||
ref="file"
|
||||
v-model="step.file"
|
||||
:options="files"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:placeholder="$t('select_file')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:id="'id_step_' + step.id + '_file'"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="files_loading"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
@search-change="searchFiles"
|
||||
>
|
||||
<template v-slot:noOptions>{{ $t("empty_list") }}</template>
|
||||
</multiselect>
|
||||
<b-input-group-append>
|
||||
<b-button
|
||||
variant="primary"
|
||||
@click="
|
||||
variant="primary"
|
||||
@click="
|
||||
step_for_file_create = step
|
||||
show_file_create = true
|
||||
"
|
||||
@@ -367,24 +367,24 @@
|
||||
<div class="col-md-12">
|
||||
<label :for="'id_step_' + step.id + '_recipe'">{{ $t("Recipe") }}</label>
|
||||
<multiselect
|
||||
ref="step_recipe"
|
||||
v-model="step.step_recipe"
|
||||
:options="recipes.map((recipe) => recipe.id)"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_recipe')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:id="'id_step_' + step.id + '_recipe'"
|
||||
:custom-label="(opt) => recipes.find((x) => x.id === opt).name"
|
||||
:multiple="false"
|
||||
:loading="recipes_loading"
|
||||
@search-change="searchRecipes"
|
||||
ref="step_recipe"
|
||||
v-model="step.step_recipe"
|
||||
:options="recipes.map((recipe) => recipe.id)"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_recipe')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:id="'id_step_' + step.id + '_recipe'"
|
||||
:custom-label="(opt) => recipes.find((x) => x.id === opt).name"
|
||||
:multiple="false"
|
||||
:loading="recipes_loading"
|
||||
@search-change="searchRecipes"
|
||||
>
|
||||
<template v-slot:noOptions>{{ $t("empty_list") }}</template>
|
||||
</multiselect>
|
||||
@@ -424,12 +424,12 @@
|
||||
<div class="col-lg-2 col-md-6 small-padding"
|
||||
v-if="!ingredient.is_header">
|
||||
<input
|
||||
class="form-control"
|
||||
v-model="ingredient.amount"
|
||||
type="number"
|
||||
step="any"
|
||||
v-if="!ingredient.no_amount"
|
||||
:id="`amount_${step_index}_${index}`"
|
||||
class="form-control"
|
||||
v-model="ingredient.amount"
|
||||
type="number"
|
||||
step="any"
|
||||
v-if="!ingredient.no_amount"
|
||||
:id="`amount_${step_index}_${index}`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -437,29 +437,29 @@
|
||||
v-if="!ingredient.is_header">
|
||||
<!-- search set to false to allow API to drive results & order -->
|
||||
<multiselect
|
||||
v-if="!ingredient.no_amount"
|
||||
ref="unit"
|
||||
v-model="ingredient.unit"
|
||||
:options="units"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_unit')"
|
||||
:tag-placeholder="$t('Create')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addUnitType"
|
||||
:id="`unit_${step_index}_${index}`"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="units_loading"
|
||||
@search-change="searchUnits"
|
||||
v-if="!ingredient.no_amount"
|
||||
ref="unit"
|
||||
v-model="ingredient.unit"
|
||||
:options="units"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_unit')"
|
||||
:tag-placeholder="$t('Create')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addUnitType"
|
||||
:id="`unit_${step_index}_${index}`"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="units_loading"
|
||||
@search-change="searchUnits"
|
||||
>
|
||||
<template v-slot:noOptions>{{
|
||||
$t("empty_list")
|
||||
@@ -472,28 +472,28 @@
|
||||
<!-- search set to false to allow API to drive results & order -->
|
||||
|
||||
<multiselect
|
||||
ref="food"
|
||||
v-model="ingredient.food"
|
||||
:options="foods"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_food')"
|
||||
:tag-placeholder="$t('Create')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addFoodType"
|
||||
:id="`ingredient_${step_index}_${index}`"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="foods_loading"
|
||||
@search-change="searchFoods"
|
||||
ref="food"
|
||||
v-model="ingredient.food"
|
||||
:options="foods"
|
||||
:close-on-select="true"
|
||||
:clear-on-select="true"
|
||||
:allow-empty="true"
|
||||
:preserve-search="true"
|
||||
:internal-search="false"
|
||||
:limit="options_limit"
|
||||
:placeholder="$t('select_food')"
|
||||
:tag-placeholder="$t('Create')"
|
||||
:select-label="$t('Select')"
|
||||
:selected-label="$t('Selected')"
|
||||
:deselect-label="$t('remove_selection')"
|
||||
:taggable="true"
|
||||
@tag="addFoodType"
|
||||
:id="`ingredient_${step_index}_${index}`"
|
||||
label="name"
|
||||
track-by="name"
|
||||
:multiple="false"
|
||||
:loading="foods_loading"
|
||||
@search-change="searchFoods"
|
||||
>
|
||||
<template v-slot:noOptions>{{
|
||||
$t("empty_list")
|
||||
@@ -504,11 +504,11 @@
|
||||
<div class="small-padding"
|
||||
v-bind:class="{ 'col-lg-4 col-md-6': !ingredient.is_header, 'col-lg-12 col-md-12': ingredient.is_header }">
|
||||
<input
|
||||
class="form-control"
|
||||
maxlength="256"
|
||||
v-model="ingredient.note"
|
||||
v-bind:placeholder="$t('Note')"
|
||||
v-on:keydown.tab="
|
||||
class="form-control"
|
||||
maxlength="256"
|
||||
v-model="ingredient.note"
|
||||
v-bind:placeholder="$t('Note')"
|
||||
v-on:keydown.tab="
|
||||
(event) => {
|
||||
if (step.ingredients.indexOf(ingredient) === step.ingredients.length - 1) {
|
||||
event.preventDefault()
|
||||
@@ -522,13 +522,13 @@
|
||||
|
||||
<div class="flex-grow-0 small-padding">
|
||||
<a
|
||||
class="btn shadow-none btn-lg pr-1 pl-0 pr-md-2 pl-md-2"
|
||||
href="#"
|
||||
role="button"
|
||||
id="dropdownMenuLink2"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
class="btn shadow-none btn-lg pr-1 pl-0 pr-md-2 pl-md-2"
|
||||
href="#"
|
||||
role="button"
|
||||
id="dropdownMenuLink2"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-ellipsis-v text-muted"></i>
|
||||
</a>
|
||||
@@ -645,7 +645,18 @@
|
||||
<mavon-editor v-model="step.instruction" :autofocus="false"
|
||||
style="z-index: auto" :id="'id_instruction_' + step.id"
|
||||
:language="'en'"
|
||||
:toolbars="md_editor_toolbars" :defaultOpen="'edit'"/>
|
||||
:toolbars="md_editor_toolbars" :defaultOpen="'edit'">
|
||||
<template #left-toolbar-after>
|
||||
<span class="op-icon-divider"></span>
|
||||
<button
|
||||
type="button"
|
||||
@click="step.instruction+= ' {{ scale(100) }}'"
|
||||
class="op-icon fas fa-times"
|
||||
aria-hidden="true"
|
||||
title="Scalable Number"
|
||||
></button>
|
||||
</template>
|
||||
</mavon-editor>
|
||||
|
||||
<!-- TODO markdown DOCS link and markdown editor -->
|
||||
</div>
|
||||
@@ -662,7 +673,7 @@
|
||||
</button>
|
||||
|
||||
<button type="button" v-b-modal:id_modal_sort class="btn btn-warning shadow-none"><i
|
||||
class="fas fa-sort-amount-down-alt fa-lg"></i></button>
|
||||
class="fas fa-sort-amount-down-alt fa-lg"></i></button>
|
||||
</b-button-group>
|
||||
</div>
|
||||
</div>
|
||||
@@ -694,7 +705,7 @@
|
||||
<div class="col-3 col-md-6 mb-1 mb-md-0 pr-2 pl-2">
|
||||
<a :href="resolveDjangoUrl('delete_recipe', recipe.id)"
|
||||
class="d-block d-md-none btn btn-block btn-danger shadow-none btn-sm"><i
|
||||
class="fa fa-trash fa-lg"></i></a>
|
||||
class="fa fa-trash fa-lg"></i></a>
|
||||
<a :href="resolveDjangoUrl('delete_recipe', recipe.id)"
|
||||
class="d-none d-md-block btn btn-block btn-danger shadow-none btn-sm">{{ $t("Delete") }}</a>
|
||||
</div>
|
||||
@@ -749,11 +760,11 @@
|
||||
|
||||
<!-- modal for pasting list of ingredients -->
|
||||
<b-modal
|
||||
id="id_modal_paste_ingredients"
|
||||
v-bind:title="$t('ingredient_list')"
|
||||
@ok="appendIngredients(paste_step)"
|
||||
@cancel="paste_ingredients = paste_step = undefined"
|
||||
@close="paste_ingredients = paste_step = undefined"
|
||||
id="id_modal_paste_ingredients"
|
||||
v-bind:title="$t('ingredient_list')"
|
||||
@ok="appendIngredients(paste_step)"
|
||||
@cancel="paste_ingredients = paste_step = undefined"
|
||||
@close="paste_ingredients = paste_step = undefined"
|
||||
>
|
||||
<b-form-textarea id="paste_ingredients" v-model="paste_ingredients"
|
||||
:placeholder="$t('paste_ingredients_placeholder')" rows="10"></b-form-textarea>
|
||||
@@ -832,7 +843,7 @@ export default {
|
||||
header: true,
|
||||
underline: true,
|
||||
strikethrough: true,
|
||||
mark: true,
|
||||
mark: false,
|
||||
superscript: true,
|
||||
subscript: true,
|
||||
quote: true,
|
||||
@@ -1293,7 +1304,7 @@ export default {
|
||||
})
|
||||
Promise.allSettled(promises).then(() => {
|
||||
ing_list.forEach(ing => {
|
||||
if(ing.trim() !== ""){
|
||||
if (ing.trim() !== "") {
|
||||
step.ingredients.push(parsed_ing_list.find(x => x.original_text === ing))
|
||||
}
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,48 @@
|
||||
|
||||
<div id="app">
|
||||
<div>
|
||||
<markdown-editor-component></markdown-editor-component>
|
||||
|
||||
<div class="swipe-container">
|
||||
<div class="swipe-action bg-success">
|
||||
<i class="swipe-icon fa-fw fas fa-check"></i>
|
||||
</div>
|
||||
|
||||
<b-button-group class="swipe-element">
|
||||
|
||||
<div class="card flex-grow-1 btn-block p-2">
|
||||
<div class="d-flex">
|
||||
<div class="d-flex flex-column pr-2">
|
||||
<span>
|
||||
<span><i class="fas fa-check"></i> <b>100 g </b></span>
|
||||
<br/>
|
||||
</span>
|
||||
<span>
|
||||
<span><i class="fas fa-check"></i> <b>200 kg </b></span>
|
||||
<br/>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div class="d-flex flex-column flex-grow-1 align-self-center">
|
||||
Erdbeeren <br/>
|
||||
<span><small class="text-muted">vabene111</small></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<b-button variant="success">
|
||||
<i class="d-print-none fa-fw fas fa-check"></i>
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
<div class="swipe-action bg-primary justify-content-end">
|
||||
<i class="fa-fw fas fa-hourglass-half swipe-icon"></i>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<markdown-editor-component></markdown-editor-component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -49,5 +89,46 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.swipe-container {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
overflow-x: scroll;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
|
||||
/* scrollbar should be hidden */
|
||||
.swipe-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.swipe-container {
|
||||
scrollbar-width: none; /* For Firefox */
|
||||
}
|
||||
|
||||
/* main element should always snap into view */
|
||||
.swipe-element {
|
||||
scroll-snap-align: start;
|
||||
}
|
||||
|
||||
.swipe-icon {
|
||||
color: white;
|
||||
position: sticky;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
/* swipe-actions and element should be 100% wide */
|
||||
.swipe-action,
|
||||
.swipe-element {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.swipe-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user