Merge branch 'develop' into feature/2402-make-now-count

This commit is contained in:
vabene1111
2023-10-05 19:01:33 +02:00
committed by GitHub
279 changed files with 31295 additions and 11718 deletions

View File

@ -24,9 +24,6 @@
<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="2" style="height: inherit">
<h3>{{ book.icon }}</h3>
</b-col>
<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">
@ -142,7 +139,7 @@ export default {
let apiClient = new ApiApiFactory()
apiClient
.createRecipeBook({ name: this.$t("New_Cookbook"), description: "", icon: "", shared: [] })
.createRecipeBook({ name: this.$t("New_Cookbook"), description: "", shared: [] })
.then((result) => {
let new_book = result.data
this.refreshData()

View File

@ -18,25 +18,6 @@
{{ $t("All recipes") }}
</b-form-checkbox>
<!-- <multiselect
:searchable="true"
:disabled="disabled_multiselect"
v-model="recipe_list"
:options="recipes"
:close-on-select="false"
:clear-on-select="true"
:hide-selected="true"
:preserve-search="true"
placeholder="Select Recipes"
:taggable="false"
label="name"
track-by="id"
id="id_recipes"
:multiple="true"
:loading="recipes_loading"
@search-change="searchRecipes"
>
</multiselect> -->
<generic-multiselect
class="input-group-text m-0 p-0"
@change="recipe_list = $event.val"
@ -81,10 +62,6 @@ Vue.use(BootstrapVue)
export default {
name: "ExportView",
/*mixins: [
ResolveUrlMixin,
ToastMixin,
],*/
components: { GenericMultiselect },
mixins: [ApiMixin],
data() {
@ -92,7 +69,6 @@ export default {
export_id: window.EXPORT_ID,
loading: false,
disabled_multiselect: false,
recipe_app: "DEFAULT",
recipe_list: [],
recipes_loading: false,
@ -103,7 +79,6 @@ export default {
},
mounted() {
if (this.export_id) this.insertRequested()
// else this.searchRecipes("")
},
methods: {
insertRequested: function () {
@ -118,25 +93,10 @@ export default {
this.recipe_list.push(response.data)
})
.catch((err) => {
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH, err)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
// .then((e) => this.searchRecipes(""))
},
// searchRecipes: function (query) {
// this.recipes_loading = true
// this.genericAPI(this.Models.RECIPE, this.Actions.LIST, { query: query })
// .then((response) => {
// this.recipes = response.data.results
// this.recipes_loading = false
// })
// .catch((err) => {
// console.log(err)
// StandardToasts.makeStandardToast(this,StandardToasts.FAIL_FETCH)
// })
// },
exportRecipe: function () {
if (this.recipe_list.length < 1 && this.export_all == false && this.filter === undefined) {
makeToast(this.$t("Error"), this.$t("Select at least one recipe"), "danger")
@ -148,7 +108,7 @@ export default {
let formData = new FormData()
formData.append("type", this.recipe_app)
formData.append("all", this.export_all)
formData.append("filter", this.filter?.id ?? null)
formData.append("custom_filter", this.filter?.id ?? null)
for (var i = 0; i < this.recipe_list.length; i++) {
formData.append("recipes", this.recipe_list[i].id)

View File

@ -511,6 +511,10 @@ export default {
this.website_url = urlParams.get('url')
this.loadRecipe(this.website_url)
}
if (urlParams.has("text")) {
this.website_url = urlParams.get('text')
this.loadRecipe(this.website_url)
}
},
methods: {
/**
@ -675,12 +679,26 @@ export default {
*/
autoImport: function () {
this.collapse_visible.import = true
this.website_url_list.split('\n').forEach(r => {
this.loadRecipe(r, true, undefined).then((recipe_json) => {
let url_list = this.website_url_list.split('\n').filter(x => x.trim() !== '')
if (url_list.length > 0) {
let url = url_list.shift()
this.website_url_list = url_list.join('\n')
this.loadRecipe(url, true, undefined).then((recipe_json) => {
this.importRecipe('multi_import', recipe_json, true)
setTimeout(() => {
this.autoImport()
}, 2000)
}).catch((err) => {
})
})
this.website_url_list = ''
} else {
this.import_loading = false
this.loading = false
}
},
/**
* Import recipes with uploaded files and app integration

View File

@ -103,6 +103,7 @@
import draggable from "vuedraggable";
import stringSimilarity from "string-similarity"
import {getUserPreference} from "@/utils/utils"
export default {
name: "ImportViewStepEditor",
@ -117,6 +118,7 @@ export default {
recipe_json: undefined,
current_edit_ingredient: null,
current_edit_step: null,
user_preferences: null,
}
},
watch: {
@ -126,6 +128,7 @@ export default {
},
mounted() {
this.recipe_json = this.recipe
this.user_preferences = getUserPreference();
},
methods: {
/**
@ -138,7 +141,7 @@ export default {
let steps = []
step.instruction.split(split_character).forEach(part => {
if (part.trim() !== '') {
steps.push({'instruction': part, 'ingredients': []})
steps.push({'instruction': part, 'ingredients': [], 'show_ingredients_table': this.user_preferences.show_step_ingredients})
}
})
steps[0].ingredients = step.ingredients // put all ingredients from the original step in the ingredients of the first step of the split step list

View File

@ -1,219 +1,165 @@
<template>
<div>
<b-tabs content-class="mt-3" v-model="current_tab">
<b-tab :title="$t('Planner')" active>
<div class="row calender-row d-none d-lg-block">
<div class="col-12 calender-parent">
<calendar-view
:show-date="showDate"
:enable-date-selection="true"
class="theme-default"
:items="plan_items"
:display-period-uom="settings.displayPeriodUom"
:period-changed-callback="periodChangedCallback"
:enable-drag-drop="true"
:item-content-height="item_height"
@click-date="createEntryClick"
@drop-on-date="moveEntry"
:display-period-count="settings.displayPeriodCount"
:starting-day-of-week="settings.startingDayOfWeek"
:display-week-numbers="settings.displayWeekNumbers"
>
<template #item="{ value, weekStartDate, top }">
<meal-plan-card
:value="value"
:week-start-date="weekStartDate"
:top="top"
:detailed="detailed_items"
:item_height="item_height"
@dragstart="dragged_item = value"
@click-item="entryClick"
@open-context-menu="openContextMenu"
/>
</template>
<template #header="{ headerProps }">
<meal-plan-calender-header
ref="header"
:header-props="headerProps"
@input="setShowDate"
@delete-dragged="deleteEntry(dragged_item)"
@create-new="createEntryClick(new Date())"
@set-starting-day-back="setStartingDay(-1)"
@set-starting-day-forward="setStartingDay(1)"
:i-cal-url="iCalUrl"
:options="options"
:settings_prop="settings"
/>
</template>
</calendar-view>
</div>
</div>
<div class="row d-block d-lg-none">
<div>
<div class="col-12">
<div class="col-12 d-flex justify-content-center mt-2">
<b-button-toolbar key-nav aria-label="Toolbar with button groups">
<b-button-group class="mx-1">
<b-button v-html="'<<'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.previousPeriod)"></b-button>
</b-button-group>
<b-button-group class="mx-1">
<b-button @click="setShowDate($refs.header.headerProps.currentPeriod)"><i
class="fas fa-home"></i></b-button>
<b-form-datepicker right button-only button-variant="secondary" @context="datePickerChanged"></b-form-datepicker>
</b-button-group>
<b-button-group class="mx-1">
<b-button v-html="'>>'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.nextPeriod)"></b-button>
</b-button-group>
</b-button-toolbar>
<div class="d-none d-lg-block">
<div class="row ">
<div class="col col-2">
<h4>{{ $t('Meal_Types') }}</h4>
<div class="d-flex flex-row align-items-center border" v-for="mt in meal_types" v-bind:key="mt.id">
<div class="flex-column" style="width: 2.5rem; height: 2.5rem;" :style="{'background-color': mt.color}"></div>
<div class="flex-column flex-grow-1 align-middle justify-content-center">
<div class="card-body p-2 align-middle">
{{ mt.name }}
</div>
</div>
<div class="col-12 mt-2" style="padding-bottom: 60px">
<div v-for="day in mobileSimpleGrid" v-bind:key="day.day">
<b-list-group>
<b-list-group-item>
<div class="d-flex flex-row align-middle">
<h6 class="mb-0 mt-1 align-middle">{{ day.date_label }}</h6>
<div class="flex-grow-1 text-right">
<b-button class="btn-sm btn-outline-primary" @click="showMealPlanEditModal(null, day.create_default_date)"><i
class="fa fa-plus"></i></b-button>
</div>
</div>
</div>
</b-list-group-item>
<b-list-group-item v-for="plan in day.plan_entries" v-bind:key="plan.entry.id" >
<div class="d-flex flex-row align-items-center">
<div>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="plan.entry.recipe.image" rounded="circle" v-if="plan.entry.recipe?.image"></b-img>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="image_placeholder" rounded="circle" v-else></b-img>
<hr/>
<button class="btn btn-success shadow-none mt-1 btn-block" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus"></i> {{ $t("Create") }}
</button>
<button class="btn btn-warning shadow-none mt-1 btn-block" @click="createAutoPlan(new Date())"><i
class="fas fa-calendar-plus"></i> {{ $t("Auto_Planner") }}
</button>
<a class="btn btn-primary shadow-none mt-1 btn-blockmt-1 btn-block" :href="iCalUrl"><i class="fas fa-download"></i>
{{ $t("Export_To_ICal") }}
</a>
<a class="btn btn-info shadow-none mt-1 btn-block" :href="resolveDjangoUrl('view_settings')">
<i class="fas fa-cogs"></i> {{ $t("Settings") }}
</a>
</div>
<div class="col col-10">
<div class="row calender-row ">
<div class="col-12 calender-parent">
<calendar-view
:show-date="showDate"
:enable-date-selection="true"
class="theme-default"
:items="plan_items"
:display-period-uom="settings.displayPeriodUom"
:period-changed-callback="periodChangedCallback"
:enable-drag-drop="true"
:item-content-height="item_height"
@click-date="createEntryClick"
@drop-on-date="moveEntry"
:display-period-count="settings.displayPeriodCount"
:starting-day-of-week="settings.startingDayOfWeek"
:display-week-numbers="settings.displayWeekNumbers"
>
<template #item="{ value, weekStartDate, top }">
<meal-plan-card
:value="value"
:week-start-date="weekStartDate"
:top="top"
:detailed="detailed_items"
:item_height="item_height"
@dragstart="dragged_item = value"
@click-item="entryClick"
@open-context-menu="openContextMenu"
/>
</template>
<template #header="{ headerProps }">
<meal-plan-calender-header
ref="header"
:header-props="headerProps"
@input="setShowDate"
@delete-dragged="deleteEntry(dragged_item)"
@create-new="createEntryClick(new Date())"
@set-starting-day-back="setStartingDay(-1)"
@set-starting-day-forward="setStartingDay(1)"
:i-cal-url="iCalUrl"
:options="options"
:settings_prop="settings"
/>
</template>
</calendar-view>
</div>
</div>
</div>
</div>
</div>
<div class="row d-block d-lg-none">
<div class="row">
<div class="col">
<div class="">
<div>
<div class="col-12">
<div class="col-12 d-flex justify-content-center mt-2">
<b-button-toolbar key-nav aria-label="Toolbar with button groups">
<b-button-group class="mx-1">
<b-button v-html="'<<'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.previousPeriod)"></b-button>
</b-button-group>
<b-button-group class="mx-1">
<b-button @click="setShowDate($refs.header.headerProps.currentPeriod)"><i
class="fas fa-home"></i></b-button>
<b-form-datepicker right button-only button-variant="secondary" @context="datePickerChanged"></b-form-datepicker>
</b-button-group>
<b-button-group class="mx-1">
<b-button v-html="'>>'" class="p-2 pr-3 pl-3"
@click="setShowDate($refs.header.headerProps.nextPeriod)"></b-button>
</b-button-group>
</b-button-toolbar>
</div>
</div>
<div class="col-12 mt-2" style="padding-bottom: 60px">
<div v-for="day in mobileSimpleGrid" v-bind:key="day.day">
<b-list-group>
<b-list-group-item>
<div class="d-flex flex-row align-middle">
<h6 class="mb-0 mt-1 align-middle">{{ day.date_label }}</h6>
<div class="flex-grow-1 text-right">
<b-button class="btn-sm btn-outline-primary" @click="showMealPlanEditModal(null, day.create_default_date)"><i
class="fa fa-plus"></i></b-button>
</div>
</div>
<div class="flex-grow-1 ml-2"
style="text-overflow: ellipsis; overflow-wrap: anywhere;">
</b-list-group-item>
<b-list-group-item v-for="plan in day.plan_entries" v-bind:key="plan.entry.id">
<div class="d-flex flex-row align-items-center">
<div>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="plan.entry.recipe.image" rounded="circle" v-if="plan.entry.recipe?.image"></b-img>
<b-img style="height: 50px; width: 50px; object-fit: cover"
:src="image_placeholder" rounded="circle" v-else></b-img>
</div>
<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>
<span v-else>{{ plan.entry.title }}</span> <br/>
</span>
<span v-if="plan.entry.note" class="two-row-text">
<span v-if="plan.entry.note" class="two-row-text">
<small>{{ plan.entry.note }}</small> <br/>
</span>
<small class="text-muted">
<span v-if="plan.entry.shopping" class="font-light"><i class="fas fa-shopping-cart fa-xs "/></span>
{{ plan.entry.meal_type_name }}
<span v-if="plan.entry.recipe">
<small class="text-muted">
<span v-if="plan.entry.shopping" class="font-light"><i class="fas fa-shopping-cart fa-xs "/></span>
{{ plan.entry.meal_type_name }}
<span v-if="plan.entry.recipe">
- <i class="fa fa-clock"></i> {{ plan.entry.recipe.working_time + plan.entry.recipe.waiting_time }} {{ $t('min') }}
</span>
</small>
</small>
</div>
<div class="hover-button">
<a class="pr-2" @click.stop="openContextMenu($event, {originalItem: plan})"><i class="fas fa-ellipsis-v"></i></a>
</div>
</div>
<div class="hover-button">
<a class="pr-2" @click.stop="openContextMenu($event, {originalItem: plan})"><i class="fas fa-ellipsis-v"></i></a>
</div>
</div>
</b-list-group-item>
</b-list-group-item>
</b-list-group>
</b-list-group>
</div>
</div>
</div>
</div>
</div>
</b-tab>
<b-tab :title="$t('Settings')">
<div class="row mt-3">
<div class="col-12 col-md-3 calender-options">
<h5>{{ $t("Planner_Settings") }}</h5>
<b-form>
<b-form-group id="UomInput" :label="$t('Period')" :description="$t('Plan_Period_To_Show')"
label-for="UomInput">
<b-form-select id="UomInput" v-model="settings.displayPeriodUom"
:options="options.displayPeriodUom"></b-form-select>
</b-form-group>
<b-form-group id="PeriodInput" :label="$t('Periods')"
:description="$t('Plan_Show_How_Many_Periods')" label-for="PeriodInput">
<b-form-select id="PeriodInput" v-model="settings.displayPeriodCount"
:options="options.displayPeriodCount"></b-form-select>
</b-form-group>
<b-form-group id="DaysInput" :label="$t('Starting_Day')" :description="$t('Starting_Day')"
label-for="DaysInput">
<b-form-select id="DaysInput" v-model="settings.startingDayOfWeek"
:options="dayNames"></b-form-select>
</b-form-group>
<b-form-group id="WeekNumInput" :label="$t('Week_Numbers')">
<b-form-checkbox v-model="settings.displayWeekNumbers" name="week_num">
{{ $t("Show_Week_Numbers") }}
</b-form-checkbox>
</b-form-group>
</b-form>
</div>
<div class="col-12 col-md-9 col-lg-6">
<h5>{{ $t("Meal_Types") }}</h5>
<div>
<draggable :list="meal_types" group="meal_types" :empty-insert-threshold="10"
@sort="sortMealTypes()" ghost-class="ghost">
<b-card no-body class="mt-1 list-group-item p-2" style="cursor: move"
v-for="(meal_type, index) in meal_types" v-hover :key="meal_type.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">
{{ meal_type.icon }} {{
meal_type.name
}}<span class="float-right text-primary" style="cursor: pointer"
><i class="fa"
v-bind:class="{ 'fa-pen': !meal_type.editing, 'fa-save': meal_type.editing }"
@click="editOrSaveMealType(index)" aria-hidden="true"></i
></span>
</h5>
</div>
</div>
</b-card-header>
<b-card-body class="p-4" v-if="meal_type.editing">
<div class="form-group">
<label>{{ $t("Name") }}</label>
<input class="form-control" :placeholder="$t('Name')"
v-model="meal_type.name"/>
</div>
<div class="form-group">
<emoji-input :field="'icon'" :label="$t('Icon')"
:value="meal_type.icon"></emoji-input>
</div>
<div class="form-group">
<label>{{ $t("Color") }}</label>
<input class="form-control" type="color" name="Name"
:value="meal_type.color"
@change="meal_type.color = $event.target.value"/>
</div>
<b-form-checkbox id="checkbox-1" v-model="meal_type.default"
name="default_checkbox" class="mb-2">
{{ $t("Default") }}
</b-form-checkbox>
<button class="btn btn-danger" @click="deleteMealType(index)">{{
$t("Delete")
}}
</button>
<button class="btn btn-primary float-right" @click="editOrSaveMealType(index)">
{{ $t("Save") }}
</button>
</b-card-body>
</b-card>
</draggable>
<button class="btn btn-success float-right mt-1" @click="newMealType">
<i class="fas fa-plus"></i>
{{ $t("New_Meal_Type") }}
</button>
</div>
</div>
</div>
</b-tab>
</b-tabs>
</div>
</div>
<ContextMenu ref="menu">
<template #menu="{ contextData }">
<ContextMenuItem
@ -279,24 +225,18 @@
:create_date="mealplan_default_date"
@reload-meal-types="refreshMealTypes"
></meal-plan-edit-modal>
<div class="row d-none d-lg-block">
<div class="col-12 float-right">
<button class="btn btn-success shadow-none" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus"></i> {{ $t("Create") }}
</button>
<a class="btn btn-primary shadow-none" :href="iCalUrl"><i class="fas fa-download"></i>
{{ $t("Export_To_ICal") }}
</a>
</div>
</div>
<auto-meal-plan-modal
:modal_title="'Auto create meal plan'"
:current_period="current_period"
></auto-meal-plan-modal>
<bottom-navigation-bar :create_links="[{label:$t('Export_To_ICal'), url: iCalUrl, icon:'fas fa-download'}]">
<template #custom_create_functions>
<h6 class="dropdown-header">{{ $t('Meal_Plan')}}</h6>
<h6 class="dropdown-header">{{ $t('Meal_Plan') }}</h6>
<a class="dropdown-item" @click="createEntryClick(new Date())"><i
class="fas fa-calendar-plus fa-fw"></i> {{ $t("Create") }}</a>
</template>
</bottom-navigation-bar>
</div>
</template>
@ -311,7 +251,6 @@ import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
import MealPlanCard from "@/components/MealPlanCard"
import MealPlanEditModal from "@/components/MealPlanEditModal"
import MealPlanCalenderHeader from "@/components/MealPlanCalenderHeader"
import EmojiInput from "@/components/Modals/EmojiInput"
import moment from "moment"
import draggable from "vuedraggable"
@ -322,6 +261,8 @@ import {CalendarView, CalendarMathMixin} from "vue-simple-calendar/src/component
import {ApiApiFactory} from "@/utils/openapi/api"
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
import {useMealPlanStore} from "@/stores/MealPlanStore";
import axios from "axios";
import AutoMealPlanModal from "@/components/AutoMealPlanModal";
const {makeToast} = require("@/utils/utils")
@ -334,19 +275,28 @@ let SETTINGS_COOKIE_NAME = "mealplan_settings"
export default {
name: "MealPlanView",
components: {
AutoMealPlanModal,
MealPlanEditModal,
MealPlanCard,
CalendarView,
ContextMenu,
ContextMenuItem,
MealPlanCalenderHeader,
EmojiInput,
draggable,
BottomNavigationBar,
},
mixins: [CalendarMathMixin, ApiMixin, ResolveUrlMixin],
data: function () {
return {
AutoPlan: {
meal_types: [],
keywords: [[]],
servings: 1,
date: Date.now(),
startDay: null,
endDay: null,
shared: [],
addshopping: false
},
showDate: new Date(),
plan_entries: [],
recipe_viewed: {},
@ -357,7 +307,6 @@ export default {
displayWeekNumbers: true,
},
dragged_item: null,
current_tab: 0,
meal_types: [],
current_context_menu_item: null,
options: {
@ -397,19 +346,9 @@ export default {
detailed_items: function () {
return this.settings.displayPeriodUom === "week"
},
dayNames: function () {
let options = []
this.getFormattedWeekdayNames(this.userLocale, "long", 0).forEach((day, index) => {
options.push({text: day, value: index})
})
return options
},
userLocale: function () {
return this.getDefaultBrowserLocale
},
item_height: function () {
if (this.settings.displayPeriodUom === "week") {
return "10rem"
return "3rem"
} else {
return "1.6rem"
}
@ -432,8 +371,8 @@ export default {
grid.push({
date: moment_date,
create_default_date: moment_date.format("YYYY-MM-DD"), // improve meal plan edit modal to do formatting itself and accept dates
date_label: moment_date.format('ddd DD.MM'),
plan_entries: this.plan_items.filter((m) => moment(m.startDate).isSame(moment_date, 'day'))
date_label: moment_date.format("dd") + " " + moment_date.format("ll"),
plan_entries: this.plan_items.filter((m) => moment_date.isBetween(moment(m.startDate), moment(m.endDate), 'day', '[]'))
})
}
}
@ -441,19 +380,14 @@ export default {
}
},
mounted() {
this.$nextTick(function () {
if (this.$cookies.isKey(SETTINGS_COOKIE_NAME)) {
this.settings = Object.assign({}, this.settings, this.$cookies.get(SETTINGS_COOKIE_NAME))
}
})
this.$root.$on("change", this.updateEmoji)
this.settings = useMealPlanStore().client_settings
this.$i18n.locale = window.CUSTOM_LOCALE
moment.locale(window.CUSTOM_LOCALE)
},
watch: {
settings: {
handler() {
this.$cookies.set(SETTINGS_COOKIE_NAME, this.settings, "360d")
useMealPlanStore().updateClientSettings(this.settings)
},
deep: true,
},
@ -539,13 +473,6 @@ export default {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
})
},
updateEmoji: function (field, value) {
this.meal_types.forEach((meal_type) => {
if (meal_type.editing) {
meal_type.icon = value
}
})
},
datePickerChanged(ctx) {
this.setShowDate(ctx.selectedDate)
},
@ -567,12 +494,16 @@ export default {
moveEntry(null_object, target_date, drag_event) {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === this.dragged_item.id) {
let fromToDiff = Math.abs(moment(entry.to_date).diff(moment(entry.from_date), 'days'))
if (drag_event.ctrlKey) {
let new_entry = Object.assign({}, entry)
new_entry.date = target_date
new_entry.from_date = target_date
new_entry.to_date = moment(target_date).add(fromToDiff, 'd')
this.createEntry(new_entry)
} else {
entry.date = target_date
entry.from_date = target_date
entry.to_date = moment(target_date).add(fromToDiff, 'd')
this.saveEntry(entry)
}
}
@ -581,7 +512,8 @@ export default {
moveEntryLeft(data) {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).subtract(1, "d")
entry.from_date = moment(entry.from_date).subtract(1, "d")
entry.to_date = moment(entry.to_date).subtract(1, "d")
this.saveEntry(entry)
}
})
@ -589,7 +521,8 @@ export default {
moveEntryRight(data) {
useMealPlanStore().plan_list.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).add(1, "d")
entry.from_date = moment(entry.from_date).add(1, "d")
entry.to_date = moment(entry.to_date).add(1, "d")
this.saveEntry(entry)
}
})
@ -607,7 +540,8 @@ export default {
openEntryEdit(entry) {
this.$bvModal.show(`id_meal_plan_edit_modal`)
this.entryEditing = entry
this.entryEditing.date = moment(entry.date).format("YYYY-MM-DD")
this.entryEditing.from_date = moment(entry.from_date).format("YYYY-MM-DD")
this.entryEditing.to_date = moment(entry.to_date).format("YYYY-MM-DD")
if (this.entryEditing.recipe != null) {
this.entryEditing.title_placeholder = this.entryEditing.recipe.name
}
@ -630,21 +564,32 @@ export default {
})
},
saveEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
entry.from_date = moment(entry.from_date).format("YYYY-MM-DD")
entry.to_date = moment(entry.to_date).format("YYYY-MM-DD")
if (entry.from_date > entry.to_date) {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE)
entry.to_date = entry.from_date
} else {
useMealPlanStore().updateObject(entry)
}
useMealPlanStore().updateObject(entry)
},
createEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
entry.from_date = moment(entry.from_date).format("YYYY-MM-DD")
entry.to_date = moment(entry.to_date).format("YYYY-MM-DD")
useMealPlanStore().createObject(entry)
},
buildItem(plan_entry) {
//dirty hack to order items within a day
let date = moment(plan_entry.date).add(plan_entry.meal_type.order, "m")
let from_date = moment(plan_entry.from_date).add(plan_entry.meal_type.order, "m")
let to_date = moment(plan_entry.to_date).add(plan_entry.meal_type.order, "m")
return {
id: plan_entry.id,
startDate: date,
endDate: date,
startDate: from_date,
endDate: to_date,
entry: plan_entry,
}
},
@ -656,7 +601,11 @@ export default {
this.$bvModal.show(`id_meal_plan_edit_modal`)
})
}
},
createAutoPlan() {
this.$bvModal.show(`autoplan-modal`)
},
},
directives: {
hover: {
@ -693,7 +642,7 @@ export default {
}
.calender-row {
height: calc(100vh - 240px);
height: calc(100vh - 140px);
}
.calender-parent {

View File

@ -31,18 +31,18 @@
</div>
</div>
<!-- Image and misc properties -->
<!-- Image and misc -->
<div class="row pt-2">
<div class="col-md-6" style="max-height: 50vh; min-height: 30vh">
<input id="id_file_upload" ref="file_upload" type="file" hidden
@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>
@ -99,65 +99,53 @@
</div>
</div>
<!-- Nutrition -->
<div class="row pt-2">
<div class="col-md-12">
<div class="card border-grey">
<div class="card-header" style="display: table">
<div class="row">
<div class="col-md-9 d-table">
<h5 class="d-table-cell align-middle">{{ $t("Nutrition") }}</h5>
<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>
<div class="alert alert-info" role="alert">
{{ $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"
></generic-multiselect>
</div>
<div class="col-md-3">
<button
type="button"
@click="addNutrition()"
v-if="recipe.nutrition === null"
v-b-tooltip.hover
v-bind:title="$t('Add_nutrition_recipe')"
class="btn btn-sm btn-success shadow-none float-right"
>
<i class="fas fa-plus-circle"></i>
</button>
<button
type="button"
@click="removeNutrition()"
v-if="recipe.nutrition !== null"
v-b-tooltip.hover
v-bind:title="$t('Remove_nutrition_recipe')"
class="btn btn-sm btn-danger shadow-none float-right"
>
<i class="fas fa-trash-alt"></i>
</button>
<div class="flex-fill w-50">
<div class="input-group">
<input type="number" class="form-control" v-model="p.property_amount">
<div class="input-group-append">
<span class="input-group-text" v-if="p.property_type !== null && p.property_type.unit !== ''">{{ p.property_type.unit }}</span>
<button class="btn btn-danger" @click="deleteProperty(p)"><i class="fa fa-trash fa-fw"></i></button>
</div>
</div>
</div>
</div>
<div class="flex-row mt-2">
<div class="flex-column w-25 offset-4">
<button class="btn btn-success btn-block" @click="addProperty()"><i class="fa fa-plus"></i></button>
</div>
</div>
</div>
<b-collapse id="id_nutrition_collapse" class="mt-2" v-model="nutrition_visible">
<div class="card-body" v-if="recipe.nutrition !== null">
<b-alert show>
There is currently only very basic support for tracking nutritional information. A
<a href="https://github.com/vabene1111/recipes/issues/896" target="_blank"
rel="noreferrer nofollow">big update</a> is planned to improve on this in many
different areas.
</b-alert>
<label for="id_name"> {{ $t(energy()) }}</label>
<input class="form-control" id="id_calories" v-model="recipe.nutrition.calories"/>
<label for="id_name"> {{ $t("Carbohydrates") }}</label>
<input class="form-control" id="id_carbohydrates"
v-model="recipe.nutrition.carbohydrates"/>
<label for="id_name"> {{ $t("Fats") }}</label>
<input class="form-control" id="id_fats" v-model="recipe.nutrition.fats"/>
<label for="id_name"> {{ $t("Proteins") }}</label>
<input class="form-control" id="id_proteins" v-model="recipe.nutrition.proteins"/>
</div>
</b-collapse>
</div>
</div>
</div>
<div class="row pt-2">
<div class="col-md-12">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button squared block v-b-toggle.additional_collapse class="text-left"
variant="outline-primary">{{ $t("additional_options") }}
@ -202,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>
@ -240,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)"
@ -252,6 +240,16 @@
v-if="step_index !== recipe.steps.length - 1">
<i class="fa fa-arrow-down fa-fw"></i> {{ $t("Move_Down") }}
</button>
<!-- Show "Hide step ingredients if state is currently set to shown" -->
<button class="dropdown-item" @click="setStepShowIngredientsTable(step, false)"
v-if="step.show_ingredients_table">
<i class="op-icon fa fa-mavon-eye-slash"></i> {{ $t("hide_step_ingredients") }}
</button>
<!-- Show "Show step ingredients if state is currently set to hidden" -->
<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>
</div>
</div>
</div>
@ -282,7 +280,6 @@
@click="step.time_visible = true" v-if="!step.time_visible">
<i class="fas fa-plus-circle"></i> {{ $t("Time") }}
</b-button>
<b-button pill variant="primary" size="sm" class="ml-1 mb-1 mb-md-0"
@click="step.ingredients_visible = true" v-if="!step.ingredients_visible">
<i class="fas fa-plus-circle"></i> {{ $t("Ingredients") }}
@ -303,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')
"
@ -330,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
"
@ -370,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>
@ -427,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>
@ -440,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")
@ -475,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")
@ -507,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()
@ -525,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>
@ -573,35 +570,35 @@
</button>
<button type="button" class="dropdown-item"
v-if="!ingredient.always_use_plural_unit"
@click="ingredient.always_use_plural_unit = true">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Unit_Always") }}
</button>
<button type="button" class="dropdown-item"
v-if="!ingredient.always_use_plural_unit"
@click="ingredient.always_use_plural_unit = true">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Unit_Always") }}
</button>
<button type="button" class="dropdown-item"
v-if="ingredient.always_use_plural_unit"
@click="ingredient.always_use_plural_unit = false">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Unit_Simple") }}
</button>
<button type="button" class="dropdown-item"
v-if="ingredient.always_use_plural_unit"
@click="ingredient.always_use_plural_unit = false">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Unit_Simple") }}
</button>
<button type="button" class="dropdown-item"
v-if="!ingredient.always_use_plural_food"
@click="ingredient.always_use_plural_food = true">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Food_Always") }}
</button>
<button type="button" class="dropdown-item"
v-if="!ingredient.always_use_plural_food"
@click="ingredient.always_use_plural_food = true">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Food_Always") }}
</button>
<button type="button" class="dropdown-item"
v-if="ingredient.always_use_plural_food"
@click="ingredient.always_use_plural_food = false">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Food_Simple") }}
</button>
<button type="button" class="dropdown-item"
v-if="ingredient.always_use_plural_food"
@click="ingredient.always_use_plural_food = false">
<i class="fas fa-filter fa-fw"></i>
{{ $t("Use_Plural_Food_Simple") }}
</button>
<button type="button" class="dropdown-item"
@click="copyTemplateReference(index, ingredient)">
<i class="fas fa-code"></i>
@ -665,7 +662,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>
@ -697,7 +694,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>
@ -752,11 +749,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>
@ -782,7 +779,8 @@ import {
ResolveUrlMixin,
StandardToasts,
convertEnergyToCalories,
energyHeading
energyHeading,
getUserPreference
} from "@/utils/utils"
import Multiselect from "vue-multiselect"
import {ApiApiFactory} from "@/utils/openapi/api"
@ -825,6 +823,7 @@ export default {
show_file_create: false,
step_for_file_create: undefined,
use_plural: false,
user_preferences: undefined,
additional_visible: false,
create_food: undefined,
md_editor_toolbars: {
@ -870,9 +869,9 @@ export default {
this.searchKeywords("")
this.searchFiles("")
this.searchRecipes("")
this.$i18n.locale = window.CUSTOM_LOCALE
let apiClient = new ApiApiFactory()
this.user_preferences = getUserPreference()
apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
this.use_plural = r.data.use_plural
})
@ -937,7 +936,10 @@ export default {
// set default visibility style for each component of the step
this.recipe.steps.forEach((s) => {
this.$set(s, "time_visible", s.time !== 0)
this.$set(s, "ingredients_visible", s.ingredients.length > 0 || this.recipe.steps.length === 1)
// ingredients_visible determines whether or not the ingredients UI is shown in the edit view
// show_ingredients_table determine whether the ingredients table is shown in the read view
// these are seperate as one might want to add ingredients but not want the step-level view
this.$set(s, "ingredients_visible", s.show_ingredients_table && (s.ingredients.length > 0 || this.recipe.steps.length === 1))
this.$set(s, "instruction_visible", s.instruction !== "" || this.recipe.steps.length === 1)
this.$set(s, "step_recipe_visible", s.step_recipe !== null)
this.$set(s, "file_visible", s.file !== null)
@ -1040,6 +1042,7 @@ export default {
show_as_header: false,
time_visible: false,
ingredients_visible: true,
show_ingredients_table: this.user_preferences.show_step_ingredients,
instruction_visible: true,
step_recipe_visible: false,
file_visible: false,
@ -1095,6 +1098,9 @@ export default {
this.recipe.steps.splice(new_index < 0 ? 0 : new_index, 0, step)
this.sortSteps()
},
setStepShowIngredientsTable: function (step, show_state) {
step.show_ingredients_table = show_state
},
moveIngredient: function (step, ingredient, new_index) {
step.ingredients.splice(step.ingredients.indexOf(ingredient), 1)
step.ingredients.splice(new_index < 0 ? 0 : new_index, 0, ingredient)
@ -1121,6 +1127,14 @@ export default {
let new_keyword = {label: tag, name: tag}
this.recipe.keywords.push(new_keyword)
},
addProperty: function () {
this.recipe.properties.push(
{'property_amount': 0, 'property_type': null}
)
},
deleteProperty: function (recipe_property) {
this.recipe.properties = this.recipe.properties.filter(p => p.id !== recipe_property.id)
},
searchKeywords: function (query) {
let apiFactory = new ApiApiFactory()
@ -1258,28 +1272,34 @@ export default {
ing_list.forEach((ing) => {
if (ing.trim() !== "") {
promises.push(this.genericPostAPI("api_ingredient_from_string", {text: ing}).then((result) => {
let unit = null
if (result.data.unit !== "" && result.data.unit !== null) {
unit = {name: result.data.unit}
}
parsed_ing_list.push({
let new_ingredient = {
amount: result.data.amount,
unit: unit,
food: {name: result.data.food},
note: result.data.note,
original_text: ing,
})
}
console.log(ing, new_ingredient)
parsed_ing_list.push(new_ingredient)
}))
}
})
Promise.allSettled(promises).then(() => {
ing_list.forEach(ing => {
step.ingredients.push(parsed_ing_list.find(x => x.original_text === ing))
if(ing.trim() !== ""){
step.ingredients.push(parsed_ing_list.find(x => x.original_text === ing))
}
})
})
},
duplicateIngredient: function (step, ingredient, new_index) {
delete ingredient.id
ingredient = JSON.parse(JSON.stringify(ingredient))
step.ingredients.splice(new_index < 0 ? 0 : new_index, 0, ingredient)
}
},

File diff suppressed because it is too large Load Diff

View File

@ -1,158 +1,6 @@
<template>
<div id="app">
<template v-if="loading">
<loading-spinner></loading-spinner>
</template>
<div v-if="!loading" style="padding-bottom: 60px">
<RecipeSwitcher ref="ref_recipe_switcher" @switch="quickSwitch($event)"/>
<div class="row">
<div class="col-12" style="text-align: center">
<h3>{{ recipe.name }}</h3>
</div>
</div>
<div class="row text-center">
<div class="col col-md-12">
<recipe-rating :recipe="recipe"></recipe-rating>
<last-cooked :recipe="recipe" class="mt-2"></last-cooked>
</div>
</div>
<div class="my-auto">
<div class="col-12" style="text-align: center">
<i>{{ recipe.description }}</i>
</div>
</div>
<div style="text-align: center">
<keywords-component :recipe="recipe"></keywords-component>
</div>
<hr/>
<div class="row align-items-center">
<div class="col col-md-3">
<div class="d-flex">
<div class="my-auto mr-1">
<i class="fas fa-fw fa-user-clock fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<span class="text-primary"><b>{{ $t("Preparation") }}</b></span><br/>
{{ working_time }}
</div>
</div>
</div>
<div class="col col-md-3">
<div class="row d-flex">
<div class="my-auto mr-1">
<i class="far fa-fw fa-clock fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<span class="text-primary"><b>{{ $t("Waiting") }}</b></span><br/>
{{ waiting_time }}
</div>
</div>
</div>
<div class="col col-md-4 col-10 mt-2 mt-md-0">
<div class="d-flex">
<div class="my-auto mr-1">
<i class="fas fa-fw fa-pizza-slice fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<CustomInputSpinButton v-model.number="servings"/>
</div>
<div class="my-auto mr-1">
<span class="text-primary">
<b>
<template v-if="recipe.servings_text === ''">{{ $t("Servings") }}</template>
<template v-else>{{ recipe.servings_text }}</template>
</b>
</span>
</div>
</div>
</div>
<div class="col col-md-2 col-2 mt-2 mt-md-0 text-right">
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"
:disabled_options="{print:false}"></recipe-context-menu>
</div>
</div>
<hr/>
<div class="row">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2"
v-if="recipe && ingredient_count > 0 && (recipe.show_ingredient_overview || recipe.steps.length < 2)">
<ingredients-card
:recipe="recipe.id"
:steps="recipe.steps"
:ingredient_factor="ingredient_factor"
:servings="servings"
:header="true"
id="ingredient_container"
@checked-state-changed="updateIngredientCheckedState"
@change-servings="servings = $event"
/>
</div>
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
<div class="row">
<div class="col-12">
<img class="img img-fluid rounded" :src="recipe.image" :alt="$t('Recipe_Image')"
v-if="recipe.image !== null" @load="onImgLoad"
:style="{ 'max-height': ingredient_height }"/>
</div>
</div>
</div>
</div>
<template v-if="!recipe.internal">
<div v-if="recipe.file_path.includes('.pdf')">
<PdfViewer :recipe="recipe"></PdfViewer>
</div>
<div
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg') || recipe.file_path.includes('.gif')">
<ImageViewer :recipe="recipe"></ImageViewer>
</div>
</template>
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
<step-component
:recipe="recipe"
:step="s"
:ingredient_factor="ingredient_factor"
:index="index"
:start_time="start_time"
@update-start-time="updateStartTime"
@checked-state-changed="updateIngredientCheckedState"
></step-component>
</div>
<div v-if="recipe.source_url !== null">
<h6 class="d-print-none"><i class="fas fa-file-import"></i> {{ $t("Imported_From") }}</h6>
<span class="text-muted mt-1"><a style="overflow-wrap: break-word;"
:href="recipe.source_url">{{ recipe.source_url }}</a></span>
</div>
<div class="row" style="margin-top: 2vh; ">
<div class="col-lg-6 offset-lg-3 col-12">
<Nutrition-component :recipe="recipe" id="nutrition_container"
:ingredient_factor="ingredient_factor"></Nutrition-component>
</div>
</div>
</div>
<add-recipe-to-book :recipe="recipe"></add-recipe-to-book>
<div class="row text-center d-print-none" style="margin-top: 3vh; margin-bottom: 3vh"
v-if="share_uid !== 'None' && !loading">
<div class="col col-md-12">
<import-tandoor></import-tandoor> <br/>
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)" class="mt-3">{{ $t("Report Abuse") }}</a>
</div>
</div>
<div id="app" v-if="recipe_id !== undefined">
<recipe-view-component :recipe_id="recipe_id"></recipe-view-component>
<bottom-navigation-bar></bottom-navigation-bar>
</div>
@ -163,192 +11,31 @@ import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {apiLoadRecipe} from "@/utils/api"
import RecipeContextMenu from "@/components/RecipeContextMenu"
import {ResolveUrlMixin, ToastMixin, calculateHourMinuteSplit} from "@/utils/utils"
import PdfViewer from "@/components/PdfViewer"
import ImageViewer from "@/components/ImageViewer"
import moment from "moment"
import LoadingSpinner from "@/components/LoadingSpinner"
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook"
import RecipeRating from "@/components/RecipeRating"
import LastCooked from "@/components/LastCooked"
import IngredientsCard from "@/components/IngredientsCard"
import StepComponent from "@/components/StepComponent"
import KeywordsComponent from "@/components/KeywordsComponent"
import NutritionComponent from "@/components/NutritionComponent"
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
import CustomInputSpinButton from "@/components/CustomInputSpinButton"
import {ApiApiFactory} from "@/utils/openapi/api";
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
import RecipeViewComponent from "@/components/RecipeViewComponent.vue";
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
Vue.prototype.moment = moment
Vue.use(BootstrapVue)
export default {
name: "RecipeView",
mixins: [ResolveUrlMixin, ToastMixin],
mixins: [],
components: {
ImportTandoor,
LastCooked,
RecipeRating,
PdfViewer,
ImageViewer,
IngredientsCard,
StepComponent,
RecipeContextMenu,
NutritionComponent,
KeywordsComponent,
LoadingSpinner,
AddRecipeToBook,
RecipeSwitcher,
CustomInputSpinButton,
BottomNavigationBar,
},
computed: {
ingredient_factor: function () {
return this.servings / this.recipe.servings
},
ingredient_count() {
return this.recipe?.steps.map((x) => x.ingredients).flat().length
},
working_time: function () {
return calculateHourMinuteSplit(this.recipe.working_time)
},
waiting_time: function () {
return calculateHourMinuteSplit(this.recipe.waiting_time)
},
RecipeViewComponent,
BottomNavigationBar
},
computed: {},
data() {
return {
loading: true,
recipe: undefined,
rootrecipe: undefined,
servings: 1,
servings_cache: {},
start_time: "",
share_uid: window.SHARE_UID,
wake_lock: null,
ingredient_height: '250',
recipe_id: window.RECIPE_ID
}
},
watch: {
servings(newVal, oldVal) {
this.servings_cache[this.recipe.id] = this.servings
},
},
mounted() {
this.loadRecipe(window.RECIPE_ID)
this.$i18n.locale = window.CUSTOM_LOCALE
this.requestWakeLock()
window.addEventListener('resize', this.handleResize);
},
beforeUnmount() {
this.destroyWakeLock()
},
methods: {
requestWakeLock: async function () {
if ('wakeLock' in navigator) {
try {
this.wake_lock = await navigator.wakeLock.request('screen')
document.addEventListener('visibilitychange', this.visibilityChange)
} catch (err) {
console.log(err)
}
}
},
handleResize: function () {
if (document.getElementById('nutrition_container') !== null) {
this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight
} else {
this.ingredient_height = document.getElementById('ingredient_container').clientHeight
}
},
destroyWakeLock: function () {
if (this.wake_lock != null) {
this.wake_lock.release()
.then(() => {
this.wake_lock = null
});
}
document.removeEventListener('visibilitychange', this.visibilityChange)
},
visibilityChange: async function () {
if (this.wake_lock != null && document.visibilityState === 'visible') {
await this.requestWakeLock()
}
},
loadRecipe: function (recipe_id) {
apiLoadRecipe(recipe_id).then((recipe) => {
let total_time = 0
for (let step of recipe.steps) {
for (let ingredient of step.ingredients) {
this.$set(ingredient, "checked", false)
}
step.time_offset = total_time
total_time += step.time
}
// set start time only if there are any steps with timers (otherwise no timers are rendered)
if (total_time > 0) {
this.start_time = moment().format("yyyy-MM-DDTHH:mm")
}
if (recipe.image === null) this.printReady()
this.recipe = this.rootrecipe = recipe
this.servings = this.servings_cache[this.rootrecipe.id] = recipe.servings
this.loading = false
setTimeout(() => {
this.handleResize()
}, 100)
})
},
updateStartTime: function (e) {
this.start_time = e
},
updateIngredientCheckedState: function (e) {
for (let step of this.recipe.steps) {
for (let ingredient of step.ingredients) {
if (ingredient.id === e.id) {
this.$set(ingredient, "checked", !ingredient.checked)
}
}
}
},
quickSwitch: function (e) {
if (e === -1) {
this.recipe = this.rootrecipe
this.servings = this.servings_cache[this.rootrecipe?.id ?? 1]
} else {
this.recipe = e
this.servings = this.servings_cache?.[e.id] ?? e.servings
}
},
printReady: function () {
const template = document.createElement("template");
template.id = "printReady";
document.body.appendChild(template);
},
onImgLoad: function () {
this.printReady()
},
},
methods: {},
}
</script>
<style>
#app > div > div {
break-inside: avoid;
}
</style>

View File

@ -48,17 +48,17 @@
</tr>
</thead>
<tr v-for="us in user_spaces" :key="us.id">
<td>{{ us.user.username }}</td>
<td>{{ us.user.display_name }}</td>
<td>
<generic-multiselect
class="input-group-text m-0 p-0"
@change="us.groups = $event.val; updateUserSpace(us)"
label="name"
:initial_selection="us.groups"
:model="Models.GROUP"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
:limit="10"
:multiple="true"
class="input-group-text m-0 p-0"
@change="us.groups = $event.val; updateUserSpace(us)"
label="name"
:initial_selection="us.groups"
:model="Models.GROUP"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
:limit="10"
:multiple="true"
/>
</td>
<td>
@ -90,14 +90,14 @@
<td>{{ il.email }}</td>
<td>
<generic-multiselect
class="input-group-text m-0 p-0"
@change="il.group = $event.val;"
label="name"
:initial_single_selection="il.group"
:model="Models.GROUP"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
:limit="10"
:multiple="false"
class="input-group-text m-0 p-0"
@change="il.group = $event.val;"
label="name"
:initial_single_selection="il.group"
:model="Models.GROUP"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
:limit="10"
:multiple="false"
/>
</td>
<td><input type="date" v-model="il.valid_until" class="form-control"></td>
@ -164,6 +164,15 @@
</div>
</div>
<div class="row">
<div class="col-md-12">
<h4>{{ $t('Open_Data_Import') }}</h4>
<open-data-import-component></open-data-import-component>
</div>
</div>
<div class="row mt-4">
<div class="col col-12">
<h4 class="mt-2"><i class="fas fa-trash"></i> {{ $t('Delete') }}</h4>
@ -198,6 +207,7 @@ import GenericMultiselect from "@/components/GenericMultiselect";
import GenericModalForm from "@/components/Modals/GenericModalForm";
import axios from "axios";
import VueClipboard from 'vue-clipboard2'
import OpenDataImportComponent from "@/components/OpenDataImportComponent.vue";
Vue.use(VueClipboard)
@ -206,7 +216,7 @@ Vue.use(BootstrapVue)
export default {
name: "SpaceManageView",
mixins: [ResolveUrlMixin, ToastMixin, ApiMixin],
components: {GenericMultiselect, GenericModalForm},
components: {GenericMultiselect, GenericModalForm, OpenDataImportComponent},
data() {
return {
ACTIVE_SPACE_ID: window.ACTIVE_SPACE_ID,
@ -228,8 +238,8 @@ export default {
apiFactory.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
this.space = r.data
})
apiFactory.listUserSpaces().then(r => {
this.user_spaces = r.data
apiFactory.listUserSpaces(1, 25).then(r => { //TODO build proper pagination
this.user_spaces = r.data.results
})
this.loadInviteLinks()
},
@ -239,7 +249,7 @@ export default {
if (link) {
content = localStorage.BASE_PATH + this.resolveDjangoUrl('view_invite', inviteLink.uuid)
}
this.$copyText(content)
this.$copyText(content)
},
loadInviteLinks: function () {
let apiFactory = new ApiApiFactory()

View File

@ -1,103 +1,41 @@
<template>
<div id="app">
<div class="row" v-if="food">
<div class="col-12">
<h2>{{ food.name }}</h2>
<beta-warning></beta-warning>
<div v-if="metadata !== undefined">
{{ $t('Data_Import_Info') }}
<select class="form-control" v-model="selected_version">
<option v-for="v in metadata.versions" v-bind:key="v">{{ v }}</option>
</select>
<b-checkbox v-model="update_existing" class="mt-1">{{ $t('Update_Existing_Data') }}</b-checkbox>
<b-checkbox v-model="use_metric" class="mt-1">{{ $t('Use_Metric') }}</b-checkbox>
<div v-if="selected_version !== undefined" class="mt-3">
<table class="table">
<tr>
<th>{{ $t('Datatype') }}</th>
<th>{{ $t('Number of Objects') }}</th>
<th>{{ $t('Imported') }}</th>
</tr>
<tr v-for="d in metadata.datatypes" v-bind:key="d">
<td>{{ $t(d.charAt(0).toUpperCase() + d.slice(1)) }}</td>
<td>{{ metadata[selected_version][d] }}</td>
<td>
<template v-if="import_count !== undefined">{{ import_count[d] }}</template>
</td>
</tr>
</table>
<button class="btn btn-success" @click="doImport">{{ $t('Import') }}</button>
</div>
</div>
<div class="row">
<div class="col-12">
<b-form v-if="food">
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
<generic-multiselect
@change="food.recipe = $event.val;"
:model="Models.RECIPE"
:initial_selection="food.recipe"
label="name"
:multiple="false"
:placeholder="$t('Recipe')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('OnHand_help')">
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
</b-form-group>
<b-form-group :description="$t('ignore_shopping_help')">
<b-form-checkbox v-model="food.ignore_shopping">{{ $t('Ignore_Shopping') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_selection="food.supermarket_category"
label="name"
:multiple="false"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
<hr/>
<!-- todo add conditions if false disable dont hide -->
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
<generic-multiselect
@change="food.substitute = $event.val;"
:model="Models.FOOD"
:initial_selection="food.substitute"
label="name"
:multiple="false"
:placeholder="$t('Substitutes')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('substitute_siblings_help')">
<b-form-checkbox v-model="food.substitute_siblings">{{ $t('substitute_siblings') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
<generic-multiselect
@change="food.inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('InheritFields')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('ChildInheritFields')" :description="$t('ChildInheritFields_help')">
<generic-multiselect
@change="food.child_inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.child_inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('ChildInheritFields')"
></generic-multiselect>
</b-form-group>
<!-- TODO change to a button -->
<b-form-group :description="$t('reset_children_help')">
<b-form-checkbox v-model="food.reset_inherit">{{ $t('reset_children') }}</b-form-checkbox>
</b-form-group>
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
</b-form>
</div>
</div>
</div>
</template>
@ -107,10 +45,9 @@ import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {ApiApiFactory} from "@/utils/openapi/api";
import RecipeCard from "@/components/RecipeCard.vue";
import GenericMultiselect from "@/components/GenericMultiselect.vue";
import {ApiMixin, StandardToasts} from "@/utils/utils";
import {ApiMixin, resolveDjangoUrl, StandardToasts} from "@/utils/utils";
import axios from "axios";
import BetaWarning from "@/components/BetaWarning.vue";
Vue.use(BootstrapVue)
@ -119,33 +56,39 @@ Vue.use(BootstrapVue)
export default {
name: "TestView",
mixins: [ApiMixin],
components: {
GenericMultiselect
},
components: {BetaWarning},
data() {
return {
food: undefined,
metadata: undefined,
selected_version: undefined,
update_existing: true,
use_metric: true,
import_count: undefined,
}
},
mounted() {
this.$i18n.locale = window.CUSTOM_LOCALE
let apiClient = new ApiApiFactory()
apiClient.retrieveFood('1').then((r) => {
this.food = r.data
})
axios.get(resolveDjangoUrl('api_import_open_data')).then(r => {
this.metadata = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
},
methods: {
updateFood: function () {
let apiClient = new ApiApiFactory()
apiClient.updateFood(this.food.id, this.food).then((r) => {
this.food = r.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
doImport: function () {
axios.post(resolveDjangoUrl('api_import_open_data'), {
'selected_version': this.selected_version,
'selected_datatypes': this.metadata.datatypes,
'update_existing': this.update_existing,
'use_metric': this.use_metric,
}).then(r => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
this.import_count = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
})
}
},
},
}
</script>

View File

@ -0,0 +1,155 @@
<template>
<div id="app">
<div class="row" v-if="food">
<div class="col-12">
<h2>{{ food.name }}</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<b-form v-if="food">
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
<generic-multiselect
@change="food.recipe = $event.val;"
:model="Models.RECIPE"
:initial_selection="food.recipe"
label="name"
:multiple="false"
:placeholder="$t('Recipe')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('OnHand_help')">
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
</b-form-group>
<b-form-group :description="$t('ignore_shopping_help')">
<b-form-checkbox v-model="food.ignore_shopping">{{ $t('Ignore_Shopping') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_selection="food.supermarket_category"
label="name"
:multiple="false"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
<hr/>
<!-- todo add conditions if false disable dont hide -->
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
<generic-multiselect
@change="food.substitute = $event.val;"
:model="Models.FOOD"
:initial_selection="food.substitute"
label="name"
:multiple="false"
:placeholder="$t('Substitutes')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('substitute_siblings_help')">
<b-form-checkbox v-model="food.substitute_siblings">{{ $t('substitute_siblings') }}</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
<generic-multiselect
@change="food.inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('InheritFields')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('ChildInheritFields')" :description="$t('ChildInheritFields_help')">
<generic-multiselect
@change="food.child_inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.child_inherit_fields"
label="name"
:multiple="false"
:placeholder="$t('ChildInheritFields')"
></generic-multiselect>
</b-form-group>
<!-- TODO change to a button -->
<b-form-group :description="$t('reset_children_help')">
<b-form-checkbox v-model="food.reset_inherit">{{ $t('reset_children') }}</b-form-checkbox>
</b-form-group>
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
</b-form>
</div>
</div>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {ApiApiFactory} from "@/utils/openapi/api";
import RecipeCard from "@/components/RecipeCard.vue";
import GenericMultiselect from "@/components/GenericMultiselect.vue";
import {ApiMixin, StandardToasts} from "@/utils/utils";
Vue.use(BootstrapVue)
export default {
name: "TestView",
mixins: [ApiMixin],
components: {
GenericMultiselect
},
data() {
return {
food: undefined,
}
},
mounted() {
this.$i18n.locale = window.CUSTOM_LOCALE
let apiClient = new ApiApiFactory()
apiClient.retrieveFood('1').then((r) => {
this.food = r.data
})
},
methods: {
updateFood: function () {
let apiClient = new ApiApiFactory()
apiClient.updateFood(this.food.id, this.food).then((r) => {
this.food = r.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
}
},
}
</script>
<style>
</style>

View File

@ -0,0 +1,255 @@
<template>
<b-modal :id="modal_id" size="lg" :title="modal_title" hide-footer aria-label="" @show="showModal">
<h5>{{ $t("Meal_Types") }}</h5>
<div>
<div>
<b-card no-body class="mt-1 p-2"
v-for="(meal_type, k) in AutoPlan.meal_types" :key="meal_type.id">
<b-card-header class="p-2 border-0">
<div class="row">
<div class="col-10">
<h5 class="mt-1 mb-1">
{{ meal_type.icon }} {{
meal_type.name
}}
</h5>
</div>
</div>
<div class="col-12">
<generic-multiselect
@change="genericSelectChanged"
:initial_selection="AutoPlan.keywords[meal_type]"
:parent_variable="`${k}`"
:model="Models.KEYWORD"
:placeholder="$t('Keywords, leave blank to exclude meal type')"
:limit="50"
/>
</div>
</b-card-header>
</b-card>
</div>
<div class="row-cols-1 m-3">
<b-form-input class="w-25 m-2 mb-0" :type="'number'" v-model="AutoPlan.servings"></b-form-input>
<small tabindex="-1" class="m-2 mt-0 form-text text-muted">{{ $t("Servings") }}</small>
</div>
<b-form-group class="mt-3">
<generic-multiselect
required
@change="AutoPlan.shared = $event.val"
parent_variable="entryEditing.shared"
:label="'display_name'"
:model="Models.USER_NAME"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Share')"
:limit="10"
:multiple="true"
:initial_selection="AutoPlan.shared"
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Share") }}</small>
</b-form-group>
<b-input-group v-if="!autoMealPlan">
<b-form-checkbox id="AddToShopping" v-model="mealplan_settings.addshopping"/>
<small tabindex="-1" class="form-text text-muted">{{
$t("AddToShopping")
}}</small>
</b-input-group>
<div class="">
<div class="row m-3 mb-0">
<b-form-datepicker class="col" :value-as-date="true" v-model="AutoPlan.startDay"></b-form-datepicker>
<div class="col"></div>
<b-form-datepicker class="col" :value-as-date="true" v-model="AutoPlan.endDay"></b-form-datepicker>
</div>
<div class="row align-top m-3 mt-0">
<small tabindex="-1" class="col align-text-top text-muted">{{ $t("Start Day") }}</small>
<div class="col"></div>
<small tabindex="-1" class="col align-self-end text-muted">{{ $t("End Day") }}</small>
</div>
</div>
</div>
<div class="row mt-3 mb-3">
<div class="col-12">
<b-button class="float-right" variant="primary" @click="createPlan" :disabled="loading">
<b-spinner small v-if="loading"></b-spinner>
{{ $t("Create Meal Plan") }}
</b-button>
<b-button class="" variant="danger" @click="exitPlan">{{ $t("Exit") }}</b-button>
</div>
</div>
</b-modal>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import GenericMultiselect from "@/components/GenericMultiselect"
import {ApiMixin} from "@/utils/utils"
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import VueCookies from "vue-cookies";
import moment from "moment/moment";
import {useMealPlanStore} from "@/stores/MealPlanStore";
const {ApiApiFactory} = require("@/utils/openapi/api")
const {StandardToasts} = require("@/utils/utils")
Vue.use(BootstrapVue)
Vue.use(VueCookies)
let MEALPLAN_COOKIE_NAME = "mealplan_settings"
export default {
name: "AutoMealPlanModal",
components: {
GenericMultiselect
},
props: {
modal_title: String,
modal_id: {
type: String,
default: "autoplan-modal",
},
current_period: Object
},
mixins: [ApiMixin],
data() {
return {
AutoPlan: {
meal_types: [],
keywords: [[]],
servings: 1,
date: Date.now(),
startDay: null,
endDay: null,
shared: [],
addshopping: false
},
mealplan_settings: {
addshopping: false,
},
loading: false,
}
},
watch: {
mealplan_settings: {
handler(newVal) {
this.$cookies.set(MEALPLAN_COOKIE_NAME, this.mealplan_settings)
},
deep: true,
},
},
mounted: function () {
useUserPreferenceStore().updateIfStaleOrEmpty()
},
computed: {
autoMealPlan: function () {
return useUserPreferenceStore().getStaleData()?.mealplan_autoadd_shopping
},
},
methods: {
genericSelectChanged: function (obj) {
this.AutoPlan.keywords[obj.var] = obj.val
},
showModal() {
if (this.$cookies.isKey(MEALPLAN_COOKIE_NAME)) {
this.mealplan_settings = Object.assign({}, this.mealplan_settings, this.$cookies.get(MEALPLAN_COOKIE_NAME))
}
this.refreshMealTypes()
this.AutoPlan.servings = 1
this.AutoPlan.startDay = new Date()
this.AutoPlan.endDay = this.current_period.periodEnd
useUserPreferenceStore().getData().then(userPreference => {
this.AutoPlan.shared = userPreference.plan_share
})
this.AutoPlan.addshopping = this.mealplan_settings.addshopping
this.loading = false
},
sortMealTypes() {
this.meal_types.forEach(function (element, index) {
element.order = index
})
let updated = 0
this.meal_types.forEach((meal_type) => {
let apiClient = new ApiApiFactory()
apiClient
.updateMealType(this.AutoPlan.meal_type, meal_type)
.then((e) => {
if (updated === this.meal_types.length - 1) {
this.periodChangedCallback(this.current_period)
} else {
updated++
}
})
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
})
},
refreshMealTypes() {
let apiClient = new ApiApiFactory()
Promise.resolve(apiClient.listMealTypes().then((result) => {
result.data.forEach((meal_type) => {
meal_type.editing = false
})
this.AutoPlan.meal_types = result.data
})).then(() => {
let mealArray = this.AutoPlan.meal_types
for (let i = 0; i < mealArray.length; i++) {
this.AutoPlan.keywords[i] = [];
}
}
)
},
createPlan() {
if (!this.loading) {
this.loading = true
let requests = []
for (let i = 0; i < this.AutoPlan.meal_types.length; i++) {
if (this.AutoPlan.keywords[i].length === 0) continue
requests.push(this.autoPlanThread(this.AutoPlan, i))
}
Promise.allSettled(requests).then(r => {
this.refreshEntries()
this.loading = false
this.$bvModal.hide(`autoplan-modal`)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
this.loading = false
})
}
},
async autoPlanThread(autoPlan, mealTypeIndex) {
let apiClient = new ApiApiFactory()
let data = {
"start_date": moment(autoPlan.startDay).format("YYYY-MM-DD"),
"end_date": moment(autoPlan.endDay).format("YYYY-MM-DD"),
"meal_type_id": autoPlan.meal_types[mealTypeIndex].id,
"keywords": autoPlan.keywords[mealTypeIndex],
"servings": autoPlan.servings,
"shared": autoPlan.shared,
"addshopping": autoPlan.addshopping
}
return apiClient.createAutoPlanViewSet(data)
},
refreshEntries() { //TODO move properly to MealPLanStore (save period for default refresh)
let date = this.current_period
useMealPlanStore().refreshFromAPI(moment(date.periodStart).format("YYYY-MM-DD"), moment(date.periodEnd).format("YYYY-MM-DD"))
},
exitPlan() {
this.$bvModal.hide(`autoplan-modal`)
}
},
}
</script>
<style scoped></style>

View File

@ -1,6 +1,6 @@
<template>
<!-- bottom button nav -->
<div class="fixed-bottom p-1 pt-2 pl-2 pr-2 border-top text-center d-lg-none" style="background: white">
<div class="fixed-bottom p-1 pt-2 pl-2 pr-2 border-top text-center d-lg-none d-print-none" style="background: white">
<div class="d-flex flex-row justify-content-around">
<div class="flex-column" v-if="show_button_1">
<slot name="button_1">

View File

@ -2,7 +2,7 @@
<b-card no-body v-hover>
<b-card-header class="p-4">
<h5>
{{ book_copy.icon }}&nbsp;{{ book_copy.name }}
{{ book_copy.name }}
<span class="float-right text-primary" @click="editOrSave"><i class="fa" v-bind:class="{ 'fa-pen': !editing, 'fa-save': editing }" aria-hidden="true"></i></span>
</h5>
<b-badge class="font-weight-normal mr-1" v-for="u in book_copy.shared" v-bind:key="u.id" variant="primary" pill>{{ u.display_name }}</b-badge>
@ -12,9 +12,6 @@
<label for="inputName1">{{ $t("Name") }}</label>
<input class="form-control" id="inputName1" placeholder="Name" v-model="book_copy.name" />
</div>
<div class="form-group" v-if="editing">
<emoji-input :field="'icon'" :label="$t('Icon')" :value="book_copy.icon"></emoji-input>
</div>
<div class="form-group" v-if="editing">
<label for="inputDesc1">{{ $t("Description") }}</label>
<textarea class="form-control" id="inputDesc1" rows="3" v-model="book_copy.description"> </textarea>
@ -58,12 +55,11 @@
<script>
import { ApiApiFactory } from "@/utils/openapi/api"
import { ApiMixin, StandardToasts } from "@/utils/utils"
import EmojiInput from "./Modals/EmojiInput"
import GenericMultiselect from "@/components/GenericMultiselect"
export default {
name: "CookbookEditCard",
components: { EmojiInput, GenericMultiselect },
components: { GenericMultiselect },
mixins: [ApiMixin],
props: {
book: Object,
@ -77,7 +73,6 @@ export default {
},
mounted() {
this.book_copy = this.book
this.$root.$on("change", this.updateEmoji)
},
directives: {
hover: {
@ -103,11 +98,6 @@ export default {
this.$emit("reload")
}
},
updateEmoji: function (item, value) {
if (item === "icon") {
this.book_copy.icon = value
}
},
saveData: function () {
let apiClient = new ApiApiFactory()

View File

@ -0,0 +1,422 @@
<template>
<div>
<b-modal :id="id" size="xl" @hidden="cancelAction" :body-class="`pr-3 pl-3`">
<template v-slot:modal-title>
<div class="row" v-if="food">
<div class="col-12">
<h2>{{ food.name }} <small class="text-muted" v-if="food.plural_name">{{
food.plural_name
}}</small>
</h2>
</div>
</div>
</template>
<div>
<b-tabs content-class="mt-3" v-if="food">
<b-tab title="General" active>
<b-form>
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Description')" description="">
<b-form-textarea v-model="food.description" rows="2"></b-form-textarea>
</b-form-group>
<!-- Food properties -->
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
<b-form-group :label="$t('Properties Food Amount')" description=""> <!-- TODO localize -->
<b-form-input v-model="food.properties_food_amount"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Properties Food Unit')" description=""> <!-- TODO localize -->
<generic-multiselect
@change="food.properties_food_unit = $event.val;"
:model="Models.UNIT"
:initial_single_selection="food.properties_food_unit"
label="name"
:multiple="false"
:placeholder="$t('Unit')"
></generic-multiselect>
</b-form-group>
<table class="table table-bordered">
<thead>
<tr>
<th> {{ $t('Property Amount') }}</th> <!-- TODO localize -->
<th> {{ $t('Property Type') }}</th> <!-- TODO localize -->
<th></th>
<th></th>
</tr>
</thead>
<tr v-for="fp in food.properties" v-bind:key="fp.id">
<td><input v-model="fp.property_amount" type="number"> <span
v-if="fp.property_type">{{ fp.property_type.unit }}</span></td>
<td>
<generic-multiselect
@change="fp.property_type = $event.val"
:initial_single_selection="fp.property_type"
label="name" :model="Models.PROPERTY_TYPE"
:multiple="false"/>
</td>
<td> / <span>{{ food.properties_food_amount }} <span
v-if="food.properties_food_unit !== null">{{
food.properties_food_unit.name
}}</span></span>
</td>
<td>
<a class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
class="fas fa-trash-alt"></i></a>
</td>
</tr>
</table>
<div class="text-center">
<b-button-group>
<b-btn class="btn btn-success shadow-none" @click="addProperty()"><i
class="fa fa-plus"></i>
</b-btn>
<b-btn class="btn btn-secondary shadow-none" @click="addAllProperties()"><i
class="fa fa-plus"> <i class="ml-1 fas fa-list"></i></i>
</b-btn>
</b-button-group>
</div>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_single_selection="food.supermarket_category"
label="name"
:multiple="false"
:allow_create="true"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
</b-form>
</b-tab>
<b-tab title="Conversions" @click="loadUnitConversions" v-if="this.food.id !== undefined">
<b-row v-for="uc in unit_conversions" :key="uc">
<b-col>
<span v-if="uc.id">
<b-btn class="btn btn-sm" variant="danger" @click="deleteUnitConversion(uc)"><i class="fas fa-trash-alt"></i></b-btn>
{{ uc.base_amount }}
{{ uc.base_unit.name }}
=
{{ uc.converted_amount }}
{{ uc.converted_unit.name }}
</span>
<b-form class="mt-1">
<b-input-group>
<b-input v-model="uc.base_amount" @change="uc.changed = true"></b-input>
<b-input-group-append>
<generic-multiselect
@change="uc.base_unit = $event.val; uc.changed = true"
:initial_single_selection="uc.base_unit"
label="name" :model="Models.UNIT"
:multiple="false"/>
</b-input-group-append>
</b-input-group>
<b-input-group>
<b-input v-model="uc.converted_amount" @change="uc.changed = true"></b-input>
<b-input-group-append>
<generic-multiselect
@change="uc.converted_unit = $event.val; uc.changed = true"
:initial_single_selection="uc.converted_unit"
label="name" :model="Models.UNIT"
:multiple="false"/>
</b-input-group-append>
</b-input-group>
</b-form>
</b-col>
<hr style="height: 1px"/>
</b-row>
<b-row>
<b-col class="text-center">
<b-btn variant="success" @click="addUnitConversion"><i class="fa fa-plus"></i></b-btn>
</b-col>
</b-row>
</b-tab>
<b-tab title="More">
<b-form>
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
<generic-multiselect
@change="food.recipe = $event.val;"
:model="Models.RECIPE"
:initial_single_selection="food.recipe"
label="name"
:multiple="false"
:placeholder="$t('Recipe')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('URL')" description="">
<b-form-input v-model="food.url"></b-form-input>
</b-form-group>
<b-form-group :description="$t('OnHand_help')">
<b-form-checkbox v-model="food.food_onhand">{{ $t('OnHand') }}</b-form-checkbox>
</b-form-group>
<b-form-group :description="$t('ignore_shopping_help')">
<b-form-checkbox v-model="food.ignore_shopping">{{
$t('Ignore_Shopping')
}}
</b-form-checkbox>
</b-form-group>
<hr/>
<!-- todo add conditions if false disable dont hide -->
<b-form-group :label="$t('Substitutes')" :description="$t('substitute_help')">
<generic-multiselect
@change="food.substitute = $event.val;"
:model="Models.FOOD"
:initial_selection="food.substitute"
label="name"
:multiple="true"
:placeholder="$t('Substitutes')"
></generic-multiselect>
</b-form-group>
<b-form-group :description="$t('substitute_siblings_help')">
<b-form-checkbox v-model="food.substitute_siblings">{{
$t('substitute_siblings')
}}
</b-form-checkbox>
</b-form-group>
<b-form-group :label="$t('InheritFields')" :description="$t('InheritFields_help')">
<generic-multiselect
@change="food.inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_selection="food.inherit_fields"
label="name"
:multiple="true"
:placeholder="$t('InheritFields')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('ChildInheritFields')"
:description="$t('ChildInheritFields_help')">
<generic-multiselect
@change="food.child_inherit_fields = $event.val;"
:model="Models.FOOD_INHERIT_FIELDS"
:initial_sselection="food.child_inherit_fields"
label="name"
:multiple="true"
:placeholder="$t('ChildInheritFields')"
></generic-multiselect>
</b-form-group>
<!-- TODO change to a button -->
<b-form-group :description="$t('reset_children_help')">
<b-form-checkbox v-model="food.reset_inherit">{{
$t('reset_children')
}}
</b-form-checkbox>
</b-form-group>
</b-form>
</b-tab>
</b-tabs>
</div>
<template v-slot:modal-footer>
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
</template>
</b-modal>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {ApiApiFactory} from "@/utils/openapi/api";
import GenericMultiselect from "@/components/GenericMultiselect.vue";
import {ApiMixin, formFunctions, getForm, StandardToasts} from "@/utils/utils";
Vue.use(BootstrapVue)
export default {
name: "FoodEditor",
mixins: [ApiMixin],
components: {
GenericMultiselect
},
props: {
id: {type: String, default: 'id_food_edit_modal_modal'},
show: {required: true, type: Boolean, default: false},
item1: {
type: Object,
default: undefined
},
},
watch: {
show: function () {
if (this.show) {
this.$bvModal.show(this.id)
} else {
this.$bvModal.hide(this.id)
}
},
},
data() {
return {
food: undefined,
unit_conversions: []
}
},
mounted() {
this.$bvModal.show(this.id)
this.$i18n.locale = window.CUSTOM_LOCALE
let apiClient = new ApiApiFactory()
let pf
if (this.item1.id !== undefined) {
pf = apiClient.retrieveFood(this.item1.id).then((r) => {
this.food = r.data
if (this.food.properties_food_unit === null) {
this.food.properties_food_unit = {name: 'g'}
}
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
} else {
this.food = {
name: "",
plural_name: "",
description: "",
shopping: false,
recipe: null,
url: '',
properties: [],
properties_food_amount: 100,
properties_food_unit: {name: 'g'},
food_onhand: false,
supermarket_category: null,
parent: null,
numchild: 0,
inherit_fields: [],
ignore_shopping: false,
substitute: [],
substitute_siblings: false,
substitute_children: false,
substitute_onhand: false,
child_inherit_fields: [],
}
}
},
methods: {
updateFood: function () {
let apiClient = new ApiApiFactory()
if (this.food.id !== undefined) {
apiClient.updateFood(this.food.id, this.food).then((r) => {
this.food = r.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
} else {
apiClient.createFood(this.food).then((r) => {
this.food = r.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
}
this.unit_conversions.forEach(uc => {
if (uc.changed === true) {
if (uc.id === undefined) {
apiClient.createUnitConversion(uc).then(r => {
uc = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err, true)
})
} else {
apiClient.updateUnitConversion(uc.id, uc).then(r => {
uc = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err, true)
})
}
}
})
},
addProperty: function () {
this.food.properties.push({property_type: null, property_amount: 0})
},
addAllProperties: function () {
let apiClient = new ApiApiFactory()
apiClient.listPropertyTypes().then(r => {
r.data.forEach(x => {
this.food.properties.push({property_type: x, property_amount: 0})
})
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
},
deleteProperty: function (p) {
this.food.properties = this.food.properties.filter(x => x !== p)
},
cancelAction: function () {
this.$emit("hidden", "")
},
loadUnitConversions: function () {
let apiClient = new ApiApiFactory()
apiClient.listUnitConversions(this.food.id).then(r => {
this.unit_conversions = r.data
})
},
addUnitConversion: function () {
this.unit_conversions.push(
{
food: this.food,
base_amount: 1,
base_unit: null,
converted_amount: 0,
converted_unit: null,
}
)
},
deleteUnitConversion: function (uc) {
this.unit_conversions = this.unit_conversions.filter(u => u !== uc)
let apiClient = new ApiApiFactory()
apiClient.destroyUnitConversion(uc.id).then(r => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
})
}
},
}
</script>
<style>
</style>

View File

@ -4,7 +4,7 @@
v-model="selected_objects"
:options="objects"
:close-on-select="true"
:clear-on-select="multiple"
:clear-on-select="true"
:hide-selected="multiple"
:preserve-search="true"
:internal-search="false"
@ -27,11 +27,11 @@
<script>
import Vue from "vue"
import Multiselect from "vue-multiselect"
import {ApiMixin, StandardToasts} from "@/utils/utils"
import { ApiMixin, StandardToasts } from "@/utils/utils"
export default {
name: "GenericMultiselect",
components: {Multiselect},
components: { Multiselect },
mixins: [ApiMixin],
data() {
return {
@ -43,16 +43,16 @@ export default {
}
},
props: {
placeholder: {type: String, default: undefined},
placeholder: { type: String, default: undefined },
model: {
type: Object,
default() {
return {}
},
},
label: {type: String, default: "name"},
parent_variable: {type: String, default: undefined},
limit: {type: Number, default: 25},
label: { type: String, default: "name" },
parent_variable: { type: String, default: undefined },
limit: { type: Number, default: 25 },
sticky_options: {
type: Array,
default() {
@ -69,11 +69,11 @@ export default {
type: Object,
default: undefined,
},
search_on_load: {type: Boolean, default: true},
multiple: {type: Boolean, default: true},
allow_create: {type: Boolean, default: false},
create_placeholder: {type: String, default: "You Forgot to Add a Tag Placeholder"},
clear: {type: Number},
search_on_load: { type: Boolean, default: true },
multiple: { type: Boolean, default: true },
allow_create: { type: Boolean, default: false },
create_placeholder: { type: String, default: "You Forgot to Add a Tag Placeholder" },
clear: { type: Number },
},
watch: {
initial_selection: function (newVal, oldVal) {
@ -84,12 +84,12 @@ export default {
empty[this.label] = `..${this.$t("loading")}..`
this.selected_objects.forEach((x) => {
if (typeof x !== "object") {
this.selected_objects[this.selected_objects.indexOf(x)] = {...empty, id: x}
this.selected_objects[this.selected_objects.indexOf(x)] = { ...empty, id: x }
get_details.push(x)
}
})
get_details.forEach((x) => {
this.genericAPI(this.model, this.Actions.FETCH, {id: x})
this.genericAPI(this.model, this.Actions.FETCH, { id: x })
.then((result) => {
// this.selected_objects[this.selected_objects.map((y) => y.id).indexOf(x)] = result.data
Vue.set(this.selected_objects, this.selected_objects.map((y) => y.id).indexOf(x), result.data)
@ -105,8 +105,8 @@ export default {
if (typeof this.selected_objects !== "object") {
let empty = {}
empty[this.label] = `..${this.$t("loading")}..`
this.selected_objects = {...empty, id: this.selected_objects}
this.genericAPI(this.model, this.Actions.FETCH, {id: this.selected_objects})
this.selected_objects = { ...empty, id: this.selected_objects }
this.genericAPI(this.model, this.Actions.FETCH, { id: this.selected_objects })
.then((result) => {
this.selected_objects = result.data
})
@ -149,13 +149,12 @@ export default {
methods: {
// this.genericAPI inherited from ApiMixin
search: function (query) {
let options = {
page: 1,
pageSize: this.limit,
query: query,
limit: this.limit,
options: {query: {simple: 1}}, // for API endpoints that support a simple view
options: { query: { simple: 1 } }, // for API endpoints that support a simple view
}
this.genericAPI(this.model, this.Actions.LIST, options).then((result) => {
@ -183,24 +182,26 @@ export default {
}
},
selectionChanged: function () {
this.$emit("change", {var: this.parent_variable, val: this.selected_objects})
this.$emit("change", { var: this.parent_variable, val: this.selected_objects })
},
addNew(e) {
//TODO add ability to choose field name other than "name"
console.log('CREATEING NEW with -> ', e)
this.genericAPI(this.model, this.Actions.CREATE, {name: e}).then(result => {
let createdObj = result.data?.results ?? result.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
if (this.multiple) {
this.selected_objects.push(createdObj)
} else {
this.selected_objects = createdObj
}
this.objects.push(createdObj)
this.selectionChanged()
}).catch((r, err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
})
console.log("CREATEING NEW with -> ", e)
this.genericAPI(this.model, this.Actions.CREATE, { name: e })
.then((result) => {
let createdObj = result.data?.results ?? result.data
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
if (this.multiple) {
this.selected_objects.push(createdObj)
} else {
this.selected_objects = createdObj
}
this.objects.push(createdObj)
this.selectionChanged()
})
.catch((r, err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
})
},
},
}

View File

@ -12,18 +12,17 @@
<i class="far fa-check-circle text-primary" v-if="!ingredient.checked"></i>
</td>
<td class="text-nowrap" @click="done">
<span v-if="ingredient.amount !== 0 && !ingredient.no_amount"
v-html="calculateAmount(ingredient.amount)"></span>
<span v-if="ingredient.amount !== 0 && !ingredient.no_amount" v-html="calculateAmount(ingredient.amount)"></span>
</td>
<td @click="done">
<template v-if="ingredient.unit !== null && !ingredient.no_amount">
<template >
<template>
<template v-if="ingredient.unit.plural_name === '' || ingredient.unit.plural_name === null">
<span>{{ ingredient.unit.name }}</span>
</template>
<template v-else>
<span v-if="ingredient.always_use_plural_unit">{{ ingredient.unit.plural_name}}</span>
<span v-else-if="(ingredient.amount * this.ingredient_factor) > 1">{{ ingredient.unit.plural_name }}</span>
<span v-if="ingredient.always_use_plural_unit">{{ ingredient.unit.plural_name }}</span>
<span v-else-if="ingredient.amount * this.ingredient_factor > 1">{{ ingredient.unit.plural_name }}</span>
<span v-else>{{ ingredient.unit.name }}</span>
</template>
</template>
@ -31,36 +30,24 @@
</td>
<td @click="done">
<template v-if="ingredient.food !== null">
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)"
v-if="ingredient.food.recipe !== null" target="_blank"
rel="noopener noreferrer">{{ ingredient.food.name }}</a>
<template v-if="ingredient.food.recipe === null">
<template>
<template v-if="ingredient.food.plural_name === '' || ingredient.food.plural_name === null">
<span>{{ ingredient.food.name }}</span>
</template>
<template v-else>
<span v-if="ingredient.always_use_plural_food">{{ ingredient.food.plural_name }}</span>
<span v-else-if="ingredient.no_amount">{{ ingredient.food.name }}</span>
<span v-else-if="(ingredient.amount * this.ingredient_factor) > 1">{{ ingredient.food.plural_name }}</span>
<span v-else>{{ ingredient.food.name }}</span>
</template>
</template>
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)" v-if="ingredient.food.recipe !== null" target="_blank" rel="noopener noreferrer">
{{ ingredientName(ingredient) }}
</a>
<a :href="ingredient.food.url" v-else-if="ingredient.food.url !== ''" target="_blank" rel="noopener noreferrer">
{{ ingredientName(ingredient) }}</a>
<template v-else>
<span>{{ ingredientName(ingredient) }}</span>
</template>
</template>
</td>
<td v-if="detailed">
<div v-if="ingredient.note">
<span v-b-popover.hover="ingredient.note" class="d-print-none touchable p-0 pl-md-2 pr-md-2">
<template v-if="ingredient.note">
<span v-b-popover.hover="ingredient.note" class="d-print-none touchable py-0 px-2">
<i class="far fa-comment"></i>
</span>
<div class="d-none d-print-block"><i class="far fa-comment-alt d-print-none"></i> {{
ingredient.note
}}
</div>
</div>
<div class="d-none d-print-block"><i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }}</div>
</template>
</td>
</template>
</tr>
@ -70,9 +57,9 @@
import {calculateAmount, ResolveUrlMixin} from "@/utils/utils"
import Vue from "vue"
import VueSanitize from "vue-sanitize";
import VueSanitize from "vue-sanitize"
Vue.use(VueSanitize);
Vue.use(VueSanitize)
export default {
name: "IngredientComponent",
@ -89,7 +76,6 @@ export default {
},
watch: {},
mounted() {
},
methods: {
calculateAmount: function (x) {
@ -99,6 +85,20 @@ export default {
done: function () {
this.$emit("checked-state-changed", this.ingredient)
},
ingredientName: function (ingredient) {
if (ingredient.food.plural_name == null || ingredient.food.plural_name === '') {
return ingredient.food.name
}
if (ingredient.always_use_plural_food) {
return ingredient.food.plural_name
} else if (ingredient.no_amount) {
return ingredient.food.name
} else if (ingredient.amount * this.ingredient_factor > 1) {
return ingredient.food.plural_name
} else {
return ingredient.food.name
}
}
},
}
</script>
@ -106,9 +106,9 @@ export default {
<style scoped>
/* increase size of hover/touchable space without changing spacing */
.touchable {
padding-right: 2em;
padding-left: 2em;
margin-right: -2em;
margin-left: -2em;
/* padding-right: 2em;
padding-left: 2em; */
margin-right: -1em;
margin-left: -1em;
}
</style>

View File

@ -1,8 +1,14 @@
<template>
<div v-if="recipe.keywords.length > 0">
<span :key="k.id" v-for="k in recipe.keywords.slice(0,keyword_splice).filter((kk) => { return kk.show || kk.show === undefined })" class="pl-1">
<a :href="`${resolveDjangoUrl('view_search')}?keyword=${k.id}`"><b-badge pill variant="light"
class="font-weight-normal">{{ k.label }}</b-badge></a>
<template v-if="enable_keyword_links">
<a :href="`${resolveDjangoUrl('view_search')}?keyword=${k.id}`">
<b-badge pill variant="light" class="font-weight-normal">{{ k.label }}</b-badge>
</a>
</template>
<template v-else>
<b-badge pill variant="light" class="font-weight-normal">{{ k.label }}</b-badge>
</template>
</span>
</div>
@ -18,10 +24,11 @@ export default {
props: {
recipe: Object,
limit: Number,
enable_keyword_links: {type: Boolean, default: true}
},
computed: {
keyword_splice: function (){
if(this.limit){
keyword_splice: function () {
if (this.limit) {
return this.limit
}
return this.recipe.keywords.lenght

View File

@ -1,6 +1,6 @@
<template>
<div>
<span class="pl-1" v-if="recipe.last_cooked !== null">
<span class="pl-1" v-if="recipe.last_cooked !== undefined && recipe.last_cooked !== null">
<b-badge pill variant="primary" class="font-weight-normal"><i class="fas fa-utensils"></i> {{
formatDate(recipe.last_cooked)
}}</b-badge>

View File

@ -29,7 +29,7 @@
<b-form-select class="ml-1" id="UomInput" v-model="settings.displayPeriodCount" :options="options.displayPeriodCount"></b-form-select>
</span>
<span
class="delete-area text-danger p-1 mr-2 ml-1 d-none d-sm-flex align-items-center"
class="delete-area text-danger p-1 mr-2 ml-1 d-none d-sm-flex align-items-center rounded"
@drop.prevent="onDeleteDrop($event)"
@dragenter.prevent="onDeleteDragEnter($event)"
@dragleave.prevent="onDeleteDragLeave($event)"

View File

@ -1,55 +1,34 @@
<template>
<div
v-hover
class="card cv-item meal-plan-card p-0"
:key="value.id"
:draggable="true"
:style="`top:${top};max-height:${item_height}`"
@dragstart="onDragItemStart(value, $event)"
@click="onClickItem(value, $event)"
:aria-grabbed="value == currentDragItem"
:class="value.classes"
@contextmenu.prevent="$emit('open-context-menu', $event, value)"
>
<div class="card-header p-1 text-center text-primary border-bottom-0" v-if="detailed" :style="`background-color: ${background_color}`">
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null">{{ entry.entry.meal_type.icon }}</span>
<span class="font-light d-none d-md-inline">{{ entry.entry.meal_type.name }}</span>
<span v-if="entry.entry.shopping" class="font-light"><i class="fas fa-shopping-cart fa-xs float-left" v-b-tooltip.hover.top :title="$t('in_shopping')" /></span>
</div>
<div class="card-img-overlay h-100 d-flex flex-column justify-content-right float-right text-right p-0" v-if="detailed">
<a>
<div style="position: static">
<div class="dropdown b-dropdown position-static btn-group">
<button
aria-haspopup="true"
aria-expanded="false"
type="button"
class="btn btn-link text-decoration-none text-body pr-2 dropdown-toggle-no-caret"
@click.stop="$emit('open-context-menu', $event, value)"
>
<i class="fas fa-ellipsis-v fa-lg"></i>
</button>
</div>
<div v-hover
class="card cv-item meal-plan-card p-0"
:key="value.id"
:draggable="true"
:style="{'top': top, 'height': item_height, 'border-color': entry.entry.meal_type.color}"
@dragstart="onDragItemStart(value, $event)"
@click="onClickItem(value, $event)"
:aria-grabbed="value == currentDragItem"
:class="value.classes"
@contextmenu.prevent="$emit('open-context-menu', $event, value)">
<div class="d-flex flex-row align-items-center">
<div class="flex-column">
<img class="" style="object-fit: cover" :style="{'height': item_height, 'width': item_height}" :src="entry.entry.recipe.image"
v-if="hasRecipe && detailed"/>
<img class="" style="object-fit: cover" :style="{'height': item_height, 'width': item_height}" :src="image_placeholder"
v-if="detailed && ((!hasRecipe && entry.entry.note === '') || (hasRecipe && entry.entry.recipe.image === null))"/>
</div>
<div class="flex-column flex-grow-0 align-middle justify-content-center">
<div class="card-body p-0 pl-1 align-middle">
<span class="font-light" :class="{'two-line-text': detailed,'one-line-text': !detailed,}">
<i class="fas fa-shopping-cart fa-xs float-left" v-b-tooltip.hover.top :title="$t('in_shopping')" v-if="entry.entry.shopping"/>
{{ title }}</span>
</div>
</a>
</div>
<div class="card-header p-1 text-center" v-if="detailed" :style="`background-color: ${background_color}`">
<span class="font-light">{{ title }}</span>
</div>
<b-img fluid class="card-img-bottom" :src="entry.entry.recipe.image" v-if="hasRecipe && detailed"></b-img>
<b-img fluid class="card-img-bottom" :src="image_placeholder" v-if="detailed && ((!hasRecipe && entry.entry.note === '') || (hasRecipe && entry.entry.recipe.image === null))"></b-img>
<div class="card-body p-1" v-if="detailed && entry.entry.recipe == null" :style="`background-color: ${background_color}`">
<p>{{ entry.entry.note }}</p>
</div>
<div class="row p-1 flex-nowrap" v-if="!detailed" :style="`background-color: ${background_color}`">
<div class="col-2">
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null" v-b-tooltip.hover.left :title="entry.entry.meal_type.name">{{ entry.entry.meal_type.icon }}</span>
<span class="font-light text-center" v-if="entry.entry.meal_type.icon == null" v-b-tooltip.hover.left :title="entry.entry.meal_type.name"></span>
</div>
<div class="col-10 d-inline-block text-truncate" :style="`max-height:${item_height}`">
<span class="font-light">{{ title }}</span>
</div>
</div>
</div>
</template>
@ -71,7 +50,8 @@ export default {
image_placeholder: window.IMAGE_PLACEHOLDER,
}
},
mounted() {},
mounted() {
},
computed: {
entry: function () {
return this.value.originalItem
@ -133,4 +113,22 @@ export default {
font-size: 13px;
}
}
.two-line-text {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.one-line-text {
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -6,14 +6,13 @@
<div class="row">
<div class="col col-md-12">
<div class="row">
<div class="col-6 col-lg-9">
<div class="col-12">
<b-input-group>
<b-form-input id="TitleInput" v-model="entryEditing.title"
:placeholder="entryEditing.title_placeholder"
@change="missing_recipe = false"></b-form-input>
<b-input-group-append class="d-none d-lg-block">
<b-button variant="primary" @click="entryEditing.title = ''"><i
class="fa fa-eraser"></i></b-button>
<b-button variant="primary" @click="entryEditing.title = ''"><i class="fa fa-eraser"></i></b-button>
</b-input-group-append>
</b-input-group>
<span class="text-danger" v-if="missing_recipe">{{
@ -23,13 +22,30 @@
$t("Title")
}}</small>
</div>
<div class="col-6 col-lg-3">
<input type="date" id="DateInput" class="form-control" v-model="entryEditing.date"/>
<small tabindex="-1" class="form-text text-muted">{{ $t("Date") }}</small>
<div class="col-12 col-lg-6">
<b-input-group>
<b-form-input type="date" v-model="entryEditing.from_date"></b-form-input>
<b-input-group-append>
<b-button variant="secondary" @click="entryEditing.from_date = changeDate(entryEditing.from_date, -1)"><i class="fas fa-minus"></i></b-button>
<b-button variant="primary" @click="entryEditing.from_date = changeDate(entryEditing.from_date, 1)"><i class="fas fa-plus"></i></b-button>
</b-input-group-append>
</b-input-group>
<small tabindex="-1" class="form-text text-muted">{{ $t("StartDate") }}</small>
</div>
<div class="col-12 col-lg-6">
<b-input-group>
<b-form-input type="date" v-model="entryEditing.to_date"></b-form-input>
<b-input-group-append>
<b-button variant="secondary" @click="entryEditing.to_date = changeDate(entryEditing.to_date, -1)"><i class="fas fa-minus"></i></b-button>
<b-button variant="primary" @click="entryEditing.to_date = changeDate(entryEditing.to_date, 1)"><i class="fas fa-plus"></i></b-button>
</b-input-group-append>
</b-input-group>
<small tabindex="-1" class="form-text text-muted">{{ $t("EndDate") }}</small>
</div>
</div>
<div class="row mt-3">
<div class="col-12 col-lg-6 col-xl-6">
<div class="row">
<div class="col-12">
<b-form-group>
<generic-multiselect
@change="selectRecipe"
@ -43,7 +59,11 @@
></generic-multiselect>
<small tabindex="-1" class="form-text text-muted">{{ $t("Recipe") }}</small>
</b-form-group>
<b-form-group class="mt-3">
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6 col-xl-6">
<b-form-group class="">
<generic-multiselect
required
@change="selectMealType"
@ -135,14 +155,14 @@ import Vue from "vue"
import VueCookies from "vue-cookies"
import {BootstrapVue} from "bootstrap-vue"
import GenericMultiselect from "@/components/GenericMultiselect"
import {ApiMixin, getUserPreference} from "@/utils/utils"
import {ApiMixin, getUserPreference, ToastMixin} from "@/utils/utils"
const {ApiApiFactory} = require("@/utils/openapi/api")
const {StandardToasts} = require("@/utils/utils")
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import {useMealPlanStore} from "@/stores/MealPlanStore";
import ShoppingModal from "@/components/Modals/ShoppingModal.vue";
import moment from "moment";
Vue.use(BootstrapVue)
Vue.use(VueCookies)
@ -163,7 +183,7 @@ export default {
default: true,
},
},
mixins: [ApiMixin],
mixins: [ApiMixin, ToastMixin],
components: {
GenericMultiselect,
RecipeCard: () => import("@/components/RecipeCard.vue"),
@ -222,7 +242,8 @@ export default {
}
if (this.create_date) {
this.entryEditing.date = this.create_date
this.entryEditing.from_date = this.create_date
this.entryEditing.to_date = this.create_date
}
useUserPreferenceStore().getData().then(userPreference => {
@ -234,9 +255,11 @@ export default {
editEntry() {
if (this.entryEditing.meal_type == null) {
this.makeToast('Warning', this.$t('Meal_Type_Required'), 'warning')
return;
}
if (this.entryEditing.recipe == null && this.entryEditing.title === "") {
this.makeToast('Warning', this.$t('Title_or_Recipe_Required'), 'warning')
return
}
//TODO properly validate
@ -289,6 +312,9 @@ export default {
this.entryEditing.servings = 1
}
},
changeDate(date, change){
return moment(date).add(change, 'd').format("YYYY-MM-DD")
}
},
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<div>
<b-form-group v-bind:label="label" class="mb-3">
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-select v-model="new_value" :placeholder="placeholder" :options="translatedOptions"></b-form-select>
</b-form-group>
</div>
@ -10,12 +10,13 @@
export default {
name: "ChoiceInput",
props: {
field: { type: String, default: "You Forgot To Set Field Name" },
label: { type: String, default: "Text Field" },
value: { type: String, default: "" },
field: {type: String, default: "You Forgot To Set Field Name"},
label: {type: String, default: "Text Field"},
value: {type: String, default: ""},
options: [],
placeholder: { type: String, default: "You Should Add Placeholder Text" },
show_merge: { type: Boolean, default: false },
placeholder: {type: String, default: "You Should Add Placeholder Text"},
show_merge: {type: Boolean, default: false},
optional: {type: Boolean, default: false},
},
data() {
return {
@ -31,9 +32,16 @@ export default {
},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
},
translatedOptions() {
return this.options.map((x) => {
return { ...x, text: this.$t(x.text) }
return {...x, text: this.$t(x.text)}
})
},
},

View File

@ -0,0 +1,46 @@
<template>
<div>
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-input v-model="new_value" type="color" ></b-form-input>
<em v-if="help" class="small text-muted">{{ help }}</em>
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
</b-form-group>
</div>
</template>
<script>
export default {
name: "ColorInput",
props: {
field: { type: String, default: "You Forgot To Set Field Name" },
label: { type: String, default: "Text Field" },
value: { type: String, default: "" },
help: { type: String, default: undefined },
subtitle: { type: String, default: undefined },
optional: {type: Boolean, default: false},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
data() {
return {
new_value: undefined,
}
},
mounted() {
this.new_value = this.value
},
watch: {
new_value: function () {
this.$root.$emit("change", this.field, this.new_value)
},
},
methods: {},
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<div>
<b-form-group v-bind:label="label" class="mb-3">
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-input v-model="new_value" type="date" ></b-form-input>
<em v-if="help" class="small text-muted">{{ help }}</em>
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
@ -17,6 +17,16 @@ export default {
value: { type: String, default: "" },
help: { type: String, default: undefined },
subtitle: { type: String, default: undefined },
optional: {type: Boolean, default: false},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
data() {
return {

View File

@ -1,54 +0,0 @@
<template>
<div>
<b-form-group
v-bind:label="label"
class="mb-3">
<input class="form-control" v-model="new_value">
<Picker :data="emojiIndex" :ref="'_edit_' + id" :native="true"
@select="setIcon"/>
</b-form-group>
</div>
</template>
<script>
import data from "emoji-mart-vue-fast/data/all.json";
import "emoji-mart-vue-fast/css/emoji-mart.css";
import {Picker, EmojiIndex} from "emoji-mart-vue-fast";
let emojiIndex = new EmojiIndex(data);
export default {
name: 'EmojiInput',
components: {Picker},
props: {
field: {type: String, default: 'You Forgot To Set Field Name'},
label: {type: String, default: ''},
value: {type: String, default: ''},
},
data() {
return {
new_value: undefined,
id: null,
emojiIndex: emojiIndex,
emojisOutput: ""
}
},
watch: {
'new_value': function () {
this.$root.$emit('change', this.field, this.new_value ?? null)
},
},
mounted() {
this.id = this._uid
},
methods: {
setIcon: function (icon) {
console.log(icon)
this.new_value = icon.native
},
}
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<div>
<b-form-group
v-bind:label="label"
v-bind:label="field_label"
class="mb-3">
<b-form-file
v-model="new_value"
@ -30,7 +30,17 @@ export default {
value: {type: String, default: ''},
placeholder: {type: String, default: ''},
show_merge: {type: Boolean, default: false},
optional: {type: Boolean, default: false},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
data() {
return {
new_value: undefined,

View File

@ -1,63 +1,83 @@
<template>
<div>
<b-modal :id="'modal_' + id" @hidden="cancelAction">
<template v-slot:modal-title>
<h4 class="d-inline">{{ form.title }}</h4>
<help-badge v-if="form.show_help" @show="show_help = true" @hide="show_help = false" :component="`GenericModal${form.title}`" />
</template>
<div v-for="(f, i) in form.fields" v-bind:key="i">
<p v-if="visibleCondition(f, 'instruction')">{{ f.label }}</p>
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help" />
<checkbox-input class="mb-3" v-if="visibleCondition(f, 'checkbox')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" />
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" />
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder" />
<emoji-input v-if="visibleCondition(f, 'emoji')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue" />
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue" />
<small-text v-if="visibleCondition(f, 'smalltext')" :value="f.value" />
<date-input v-if="visibleCondition(f, 'date')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" :subtitle="f.subtitle" />
<number-input v-if="visibleCondition(f, 'number')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" />
</div>
<template v-slot:modal-footer>
<div class="row w-100">
<div class="col-6 align-self-end">
<b-form-checkbox v-if="advancedForm" sm switch v-model="show_advanced">{{ $t("Advanced") }}</b-form-checkbox>
</div>
<div class="col-auto justify-content-end">
<b-button class="mx-1" variant="secondary" v-on:click="cancelAction">{{ $t("Cancel") }}</b-button>
<b-button class="mx-1" variant="primary" v-on:click="doAction">{{ form.ok_label }}</b-button>
</div>
<template v-if="form_component !== undefined && (action === Actions.UPDATE || action === Actions.CREATE)">
<component :is="form_component" :id="'modal_' + id" :show="show" @hidden="cancelAction" :item1="item1"></component>
</template>
<template v-else>
<b-modal :id="'modal_' + id" @hidden="cancelAction" size="lg">
<template v-slot:modal-title>
<h4 class="d-inline">{{ form.title }}</h4>
<help-badge v-if="form.show_help" @show="show_help = true" @hide="show_help = false" :component="`GenericModal${form.title}`"/>
</template>
<div v-for="(f, i) in form.fields" v-bind:key="i">
<p v-if="visibleCondition(f, 'instruction')">{{ f.label }}</p>
<lookup-input v-if="visibleCondition(f, 'lookup')" :form="f" :model="listModel(f.list)" @change="storeValue" :help="showHelp && f.help" :optional="f.optional"/>
<checkbox-input class="mb-3" v-if="visibleCondition(f, 'checkbox')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help"/>
<text-input v-if="visibleCondition(f, 'text')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled" :optional="f.optional"/>
<text-area-input v-if="visibleCondition(f, 'textarea')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :disabled="f.disabled" :optional="f.optional"/>
<choice-input v-if="visibleCondition(f, 'choice')" :label="f.label" :value="f.value" :field="f.field" :options="f.options" :placeholder="f.placeholder" :optional="f.optional"/>
<file-input v-if="visibleCondition(f, 'file')" :label="f.label" :value="f.value" :field="f.field" @change="storeValue" :optional="f.optional"/>
<small-text v-if="visibleCondition(f, 'smalltext')" :value="f.value" />
<date-input v-if="visibleCondition(f, 'date')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" :subtitle="f.subtitle" :optional="f.optional"/>
<color-input v-if="visibleCondition(f, 'color')" :label="f.label" :value="f.value" :field="f.field" :help="showHelp && f.help" :subtitle="f.subtitle" :optional="f.optional"/>
<number-input v-if="visibleCondition(f, 'number')" :label="f.label" :value="f.value" :field="f.field" :placeholder="f.placeholder" :help="showHelp && f.help" :subtitle="f.subtitle" :optional="f.optional"/>
</div>
</template>
</b-modal>
<template v-slot:modal-footer>
<div class="row w-100">
<div class="col-6 align-self-end">
<b-form-checkbox v-if="advancedForm" sm switch v-model="show_advanced">{{ $t("Advanced") }}</b-form-checkbox>
</div>
<div class="col-auto justify-content-end">
<b-button class="mx-1" variant="secondary" v-on:click="cancelAction">{{ $t("Cancel") }}</b-button>
<b-button class="mx-1" variant="primary" v-on:click="doAction">{{ form.ok_label }}</b-button>
</div>
</div>
</template>
</b-modal>
</template>
</div>
</template>
<script>
import Vue from "vue"
import { BootstrapVue } from "bootstrap-vue"
import { getForm, formFunctions } from "@/utils/utils"
import {BootstrapVue} from "bootstrap-vue"
import {getForm, formFunctions} from "@/utils/utils"
Vue.use(BootstrapVue)
import { ApiApiFactory } from "@/utils/openapi/api"
import { ApiMixin, StandardToasts, ToastMixin, getUserPreference } from "@/utils/utils"
import {ApiApiFactory} from "@/utils/openapi/api"
import {ApiMixin, StandardToasts, ToastMixin, getUserPreference} from "@/utils/utils"
import CheckboxInput from "@/components/Modals/CheckboxInput"
import LookupInput from "@/components/Modals/LookupInput"
import TextInput from "@/components/Modals/TextInput"
import DateInput from "@/components/Modals/DateInput"
import EmojiInput from "@/components/Modals/EmojiInput"
import ChoiceInput from "@/components/Modals/ChoiceInput"
import FileInput from "@/components/Modals/FileInput"
import SmallText from "@/components/Modals/SmallText"
import HelpBadge from "@/components/Badges/Help"
import NumberInput from "@/components/Modals/NumberInput.vue";
import TextAreaInput from "@/components/Modals/TextAreaInput.vue";
import ColorInput from "@/components/Modals/ColorInput.vue";
export default {
name: "GenericModalForm",
components: { FileInput, CheckboxInput, LookupInput, TextInput, EmojiInput, ChoiceInput, SmallText, HelpBadge,DateInput, NumberInput },
components: {
FileInput,
CheckboxInput,
LookupInput,
TextInput,
ChoiceInput,
SmallText,
HelpBadge,
DateInput,
NumberInput,
TextAreaInput,
ColorInput
},
mixins: [ApiMixin, ToastMixin],
props: {
model: { required: true, type: Object },
model: {required: true, type: Object},
action: {
type: Object,
default() {
@ -76,7 +96,8 @@ export default {
return {}
},
},
show: { required: true, type: Boolean, default: false },
show: {required: true, type: Boolean, default: false},
models: {required: false, type: Function, default: null}
},
data() {
return {
@ -92,6 +113,10 @@ export default {
mounted() {
this.id = Math.random()
this.$root.$on("change", this.storeValue) // bootstrap modal placed at document so have to listen at root of component
if (this.models !== null) {
this.Models = this.models // override models definition file with prop
}
},
computed: {
advancedForm() {
@ -111,6 +136,15 @@ export default {
return undefined
}
},
form_component() {
// TODO this leads webpack to create one .js file for each component in this folder because at runtime any one of them could be requested
// TODO this is not necessarily bad but maybe there are better options to do this
if (this.form.component !== undefined) {
return () => import(/* webpackChunkName: "header-component" */ `@/components/${this.form.component}`)
} else {
return undefined
}
},
},
watch: {
show: function () {
@ -153,6 +187,7 @@ export default {
if (this.dirty) {
this.dirty = false
this.$emit("finish-action", "cancel")
this.$emit("hidden")
}
},
storeValue: function (field, value) {
@ -174,16 +209,16 @@ export default {
return form
},
delete: function () {
this.genericAPI(this.model, this.Actions.DELETE, { id: this.item1.id })
this.genericAPI(this.model, this.Actions.DELETE, {id: this.item1.id})
.then((result) => {
this.$emit("finish-action")
StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_DELETE)
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
})
.catch((err) => {
if (err.response.status === 403){
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE_PROTECTED, err)
}else {
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_DELETE, err)
if (err.response.status === 403) {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE_PROTECTED, err)
} else {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
}
this.$emit("finish-action", "cancel")
})
@ -193,22 +228,22 @@ export default {
// if there is no item id assume it's a new item
this.genericAPI(this.model, this.Actions.CREATE, this.form_data)
.then((result) => {
this.$emit("finish-action", { item: result.data })
StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_CREATE)
this.$emit("finish-action", {item: result.data})
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
})
.catch((err) => {
console.log(err)
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_CREATE)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE)
this.$emit("finish-action", "cancel")
})
} else {
this.genericAPI(this.model, this.Actions.UPDATE, this.form_data)
.then((result) => {
this.$emit("finish-action", { item: result.data })
StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_UPDATE)
this.$emit("finish-action", {item: result.data})
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
})
.catch((err) => {
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_UPDATE, err)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
this.$emit("finish-action", "cancel")
})
}
@ -224,13 +259,13 @@ export default {
this.$emit("finish-action", "cancel")
return
}
this.genericAPI(this.model, this.Actions.MOVE, { source: this.item1.id, target: this.form_data.target.id })
this.genericAPI(this.model, this.Actions.MOVE, {source: this.item1.id, target: this.form_data.target.id})
.then((result) => {
this.$emit("finish-action", { target: this.form_data.target.id })
StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MOVE)
this.$emit("finish-action", {target: this.form_data.target.id})
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_MOVE)
})
.catch((err) => {
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_MOVE, err)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_MOVE, err)
this.$emit("finish-action", "cancel")
})
},
@ -250,11 +285,14 @@ export default {
target: this.form_data.target.id,
})
.then((result) => {
this.$emit("finish-action", { target: this.form_data.target.id, target_object: this.form_data.target }) //TODO temporary workaround to not change other apis
StandardToasts.makeStandardToast(this,StandardToasts.SUCCESS_MERGE)
this.$emit("finish-action", {
target: this.form_data.target.id,
target_object: this.form_data.target
}) //TODO temporary workaround to not change other apis
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_MERGE)
})
.catch((err) => {
StandardToasts.makeStandardToast(this,StandardToasts.FAIL_MERGE, err)
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_MERGE, err)
this.$emit("finish-action", "cancel")
})

View File

@ -2,7 +2,7 @@
<div>
<b-form-group :class="class_list">
<template #label v-if="show_label">
{{ form.label }}
{{ field_label }}
</template>
<generic-multiselect
@change="new_value = $event.val"
@ -27,11 +27,11 @@
<script>
import GenericMultiselect from "@/components/GenericMultiselect"
import { StandardToasts, ApiMixin } from "@/utils/utils"
import {StandardToasts, ApiMixin} from "@/utils/utils"
export default {
name: "LookupInput",
components: { GenericMultiselect },
components: {GenericMultiselect},
mixins: [ApiMixin],
props: {
form: {
@ -46,11 +46,13 @@ export default {
return undefined
},
},
class_list: { type: String, default: "mb-3" },
show_label: { type: Boolean, default: true },
clear: { type: Number },
help: { type: String, default: undefined },
class_list: {type: String, default: "mb-3"},
show_label: {type: Boolean, default: true},
clear: {type: Number},
help: {type: String, default: undefined},
optional: {type: Boolean, default: false},
},
data() {
return {
new_value: undefined,
@ -67,7 +69,7 @@ export default {
this.label = this.form?.label ?? ""
this.sticky_options = this.form?.sticky_options ?? []
this.sticky_options = this.sticky_options.map((x) => {
return { ...x, name: this.$t(x.name) }
return {...x, name: this.$t(x.name)}
})
this.list_label = this.form?.list_label ?? undefined
if (this.list_label?.includes("::")) {
@ -75,6 +77,13 @@ export default {
}
},
computed: {
field_label: function () {
if (this.optional) {
return this.form.label
} else {
return this.form.label + '*'
}
},
modelName() {
return this.$t(this?.model?.name) ?? this.$t("Search")
},
@ -124,7 +133,7 @@ export default {
let item = undefined
let label = this.form.list_label.split("::")
itemlist.forEach((x) => {
item = { ...x }
item = {...x}
for (const [k, v] of Object.entries(x)) {
if (k == label[0]) {
item["id"] = v.id

View File

@ -1,6 +1,6 @@
<template>
<div>
<b-form-group v-bind:label="label" class="mb-3">
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-input v-model="new_value" type="number" :placeholder="placeholder"></b-form-input>
<em v-if="help" class="small text-muted">{{ help }}</em>
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
@ -18,6 +18,16 @@ export default {
placeholder: { type: Number, default: 0 },
help: { type: String, default: undefined },
subtitle: { type: String, default: undefined },
optional: {type: Boolean, default: false},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
data() {
return {

View File

@ -1,190 +1,194 @@
<template>
<div>
<b-modal hide-footer :id="`shopping_${this.modal_id}`" @show="loadRecipe" body-class="p-3 pt-0 pt-md-3">
<template v-slot:modal-title><h5>{{ $t("Add_Servings_to_Shopping", {servings: recipe_servings}) }}</h5></template>
<loading-spinner v-if="loading"></loading-spinner>
<div class="accordion" role="tablist" v-if="!loading">
<b-card no-body class="mb-1">
<b-card-header header-tag="header" class="p-0" role="tab">
<b-button block v-b-toggle.accordion-0 class="text-left" variant="outline-info">{{ recipe.name }}</b-button>
</b-card-header>
<b-collapse id="accordion-0" class="p-2" visible accordion="my-accordion" role="tabpanel">
<div>
<b-modal hide-footer :id="`shopping_${this.modal_id}`" @show="loadRecipe" body-class="p-3 pt-0 pt-md-3">
<template v-slot:modal-title
><h5>{{ $t("Add_Servings_to_Shopping", { servings: recipe_servings }) }}</h5></template
>
<loading-spinner v-if="loading"></loading-spinner>
<div class="accordion" role="tablist" v-if="!loading">
<b-card no-body class="mb-1">
<b-card-header header-tag="header" class="p-0" role="tab">
<b-button block v-b-toggle.accordion-0 class="text-left" variant="outline-info">{{ recipe.name }}</b-button>
</b-card-header>
<b-collapse id="accordion-0" class="p-2" visible accordion="my-accordion" role="tabpanel">
<div>
<table class="table table-sm mb-0">
<ingredient-component
v-for="i in steps.flatMap((s) => s.ingredients)"
v-bind:key="i.id"
:detailed="true"
:ingredient="i"
:ingredient_factor="ingredient_factor"
@checked-state-changed="$set(i, 'checked', !i.checked)"
/>
</table>
</div>
</b-collapse>
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
<template v-for="r in related_recipes">
<b-card no-body class="mb-1" :key="r.recipe.id">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button btn-sm block v-b-toggle="'accordion-' + r.recipe.id" class="text-left" variant="outline-primary">{{ r.recipe.name }}</b-button>
</b-card-header>
<b-collapse :id="'accordion-' + r.recipe.id" accordion="my-accordion" role="tabpanel">
<div v-for="i in r.steps.flatMap((s) => s.ingredients)" v-bind:key="i.id">
<table class="table table-sm mb-0">
<ingredient-component
:use_plural="true"
:key="i.id"
:detailed="true"
:ingredient="i"
:ingredient_factor="ingredient_factor"
@checked-state-changed="$set(i, 'checked', !i.checked)"
/>
</table>
</div>
</b-collapse>
</b-card>
</template>
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
</b-card>
</div>
<div>
<table class="table table-sm mb-0">
<div>
<b-input-group>
<b-input-group-prepend is-text class="d-inline-flex">
<i class="fa fa-calculator"></i>
</b-input-group-prepend>
<b-form-spinbutton min="1" v-model="recipe_servings" inline style="height: 3em"></b-form-spinbutton>
<!-- <CustomInputSpinButton v-model.number="recipe_servings" style="height: 3em" /> -->
<ingredient-component v-for="i in steps.flatMap(s => s.ingredients)" v-bind:key="i.id"
:detailed="true"
:ingredient="i"
:ingredient_factor="ingredient_factor"
@checked-state-changed="$set(i, 'checked', !i.checked)"
/>
</table>
</div>
</b-collapse>
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
<template v-for="r in related_recipes">
<b-card no-body class="mb-1" :key="r.recipe.id">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button btn-sm block v-b-toggle="'accordion-' + r.recipe.id" class="text-left" variant="outline-primary">{{ r.recipe.name }}</b-button>
</b-card-header>
<b-collapse :id="'accordion-' + r.recipe.id" accordion="my-accordion" role="tabpanel">
<div v-for="i in r.steps.flatMap(s => s.ingredients)" v-bind:key="i.id">
<table class="table table-sm mb-0">
<ingredient-component
:use_plural="true"
:key="i.id"
:detailed="true"
:ingredient="i"
:ingredient_factor="ingredient_factor"
@checked-state-changed="$set(i, 'checked', !i.checked)"
/>
</table>
</div>
</b-collapse>
</b-card>
</template>
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
</b-card>
</div>
<div>
<b-input-group>
<b-input-group-prepend is-text class="d-inline-flex">
<i class="fa fa-calculator"></i>
</b-input-group-prepend>
<b-form-spinbutton min="1" v-model="recipe_servings" inline style="height: 3em"></b-form-spinbutton>
<!-- <CustomInputSpinButton v-model.number="recipe_servings" style="height: 3em" /> -->
<b-input-group-append class="d-inline-flex">
<b-button variant="success" @click="saveShopping" class="d-none d-lg-inline-block">{{ $t("Save") }}</b-button>
<b-button variant="success" @click="saveShopping" class="d-inline-block d-lg-none"><i class="fa fa-cart-plus"></i></b-button>
</b-input-group-append>
</b-input-group>
</div>
</b-modal>
</div>
<b-input-group-append class="d-inline-flex">
<b-button variant="success" @click="saveShopping" class="d-none d-lg-inline-block">{{ $t("Save") }}</b-button>
<b-button variant="success" @click="saveShopping" class="d-inline-block d-lg-none"><i class="fa fa-cart-plus"></i></b-button>
</b-input-group-append>
</b-input-group>
</div>
</b-modal>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import { BootstrapVue } from "bootstrap-vue"
Vue.use(BootstrapVue)
const {ApiApiFactory} = require("@/utils/openapi/api")
import {StandardToasts} from "@/utils/utils"
const { ApiApiFactory } = require("@/utils/openapi/api")
import { StandardToasts } from "@/utils/utils"
import IngredientComponent from "@/components/IngredientComponent"
import LoadingSpinner from "@/components/LoadingSpinner"
import {useMealPlanStore} from "@/stores/MealPlanStore";
import { useMealPlanStore } from "@/stores/MealPlanStore"
// import CustomInputSpinButton from "@/components/CustomInputSpinButton"
export default {
name: "ShoppingModal",
components: {LoadingSpinner, IngredientComponent},
mixins: [],
props: {
recipe: {required: true, type: Object},
servings: {type: Number, default: undefined},
modal_id: {required: true, type: Number},
mealplan: {type: Object, default: undefined},
list_recipe: {type: Number, default: undefined},
},
data() {
return {
loading: true,
steps: [],
recipe_servings: undefined,
add_shopping: [],
related_recipes: [],
}
},
mounted() {
this.recipe_servings = this.servings
},
computed: {
ingredient_factor: function () {
return this.recipe_servings / this.recipe.servings
},
},
watch: {
servings: function (newVal) {
this.recipe_servings = parseInt(newVal)
},
},
methods: {
loadRecipe: function () {
this.add_shopping = []
this.related_recipes = []
let apiClient = new ApiApiFactory()
apiClient
.retrieveRecipe(this.recipe.id)
.then((result) => {
this.steps = result.data.steps
// ALERT: this will all break if ingredients are re-used between recipes
// ALERT: this also doesn't quite work right if the same recipe appears multiple time in the related recipes
if (!this.recipe_servings) {
this.recipe_servings = result.data?.servings
}
this.steps.forEach(s => s.ingredients.filter(i => i.food?.food_onhand === false).forEach(i => this.$set(i, 'checked', true)))
this.loading = false
})
.then(() => {
// get a list of related recipes
apiClient
.relatedRecipe(this.recipe.id)
.then((result) => {
return result.data
})
.then((related_recipes) => {
let promises = []
related_recipes.forEach((x) => {
promises.push(
apiClient.listSteps(x.id).then((recipe_steps) => {
let sub_recipe_steps = recipe_steps.data.results.filter((x) => x.ingredients.length > 0)
sub_recipe_steps.forEach(s => s.ingredients.filter(i => i.food.food_onhand === false).forEach(i => this.$set(i, 'checked', true)))
this.related_recipes.push({
recipe: x,
steps: sub_recipe_steps,
})
})
)
})
return Promise.all(promises)
})
})
},
saveShopping: function () {
// another choice would be to create ShoppingListRecipes for each recipe - this bundles all related recipe under the parent recipe
let shopping_recipe = {
id: this.recipe.id,
ingredients: this.steps.flatMap(s => s.ingredients.filter(i => i.checked === true).flatMap(i => i.id)).concat(this.related_recipes.flatMap(r => r.steps.flatMap(rs => rs.ingredients.filter(i => i.checked === true).flatMap(i => i.id)))),
servings: this.recipe_servings,
mealplan: this.mealplan,
list_recipe: this.list_recipe,
}
let apiClient = new ApiApiFactory()
apiClient.shoppingRecipe(this.recipe.id, shopping_recipe)
.then((result) => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
this.$emit("finish")
if (this.mealplan !== undefined && this.mealplan !== null){
name: "ShoppingModal",
components: { LoadingSpinner, IngredientComponent },
mixins: [],
props: {
recipe: { required: true, type: Object },
servings: { type: Number, default: undefined },
modal_id: { required: true, type: Number },
mealplan: { type: Object, default: undefined },
list_recipe: { type: Number, default: undefined },
},
data() {
return {
loading: true,
steps: [],
recipe_servings: undefined,
add_shopping: [],
related_recipes: [],
}
},
mounted() {
this.recipe_servings = this.servings
},
computed: {
ingredient_factor: function () {
return this.recipe_servings / this.recipe.servings
},
},
watch: {
servings: function (newVal) {
this.recipe_servings = parseInt(newVal)
},
},
methods: {
loadRecipe: function () {
this.add_shopping = []
this.related_recipes = []
let apiClient = new ApiApiFactory()
apiClient
.retrieveRecipe(this.recipe.id)
.then((result) => {
this.steps = result.data.steps
// ALERT: this will all break if ingredients are re-used between recipes
// ALERT: this also doesn't quite work right if the same recipe appears multiple time in the related recipes
if (!this.recipe_servings) {
this.recipe_servings = result.data?.servings
}
this.steps.forEach((s) => s.ingredients.filter((i) => i.food?.food_onhand === false).forEach((i) => this.$set(i, "checked", true)))
this.loading = false
})
.then(() => {
// get a list of related recipes
apiClient
.relatedRecipe(this.recipe.id)
.then((result) => {
return result.data
})
.then((related_recipes) => {
let promises = []
related_recipes.forEach((x) => {
promises.push(
apiClient.listSteps(x.id).then((recipe_steps) => {
let sub_recipe_steps = recipe_steps.data.results.filter((x) => x.ingredients.length > 0)
sub_recipe_steps.forEach((s) => s.ingredients.filter((i) => i.food.food_onhand === false).forEach((i) => this.$set(i, "checked", true)))
this.related_recipes.push({
recipe: x,
steps: sub_recipe_steps,
})
})
)
})
return Promise.all(promises)
})
})
},
saveShopping: function () {
// another choice would be to create ShoppingListRecipes for each recipe - this bundles all related recipe under the parent recipe
let shopping_recipe = {
id: this.recipe.id,
ingredients: this.steps
.flatMap((s) => s.ingredients.filter((i) => i.checked === true).flatMap((i) => i.id))
.concat(this.related_recipes.flatMap((r) => r.steps.flatMap((rs) => rs.ingredients.filter((i) => i.checked === true).flatMap((i) => i.id)))),
servings: this.recipe_servings,
mealplan: this.mealplan,
list_recipe: this.list_recipe,
}
let apiClient = new ApiApiFactory()
apiClient
.shoppingRecipe(this.recipe.id, shopping_recipe)
.then((result) => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
this.$emit("finish")
if (this.mealplan !== undefined && this.mealplan !== null) {
useMealPlanStore().plans[this.mealplan.id].shopping = true
}
})
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
})
})
.catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
})
this.$bvModal.hide(`shopping_${this.modal_id}`)
},
},
this.$bvModal.hide(`shopping_${this.modal_id}`)
},
},
}
</script>
<style>
.b-form-spinbutton.form-control {
background-color: #e9ecef;
border: 1px solid #ced4da;
background-color: #e9ecef;
border: 1px solid #ced4da;
}
</style>

View File

@ -0,0 +1,48 @@
<template>
<div>
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-textarea v-model="new_value" type="text" :placeholder="placeholder" :disabled="disabled"></b-form-textarea>
<em v-if="help" class="small text-muted">{{ help }}</em>
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
</b-form-group>
</div>
</template>
<script>
export default {
name: "TextAreaInput",
props: {
field: {type: String, default: "You Forgot To Set Field Name"},
label: {type: String, default: "Text Field"},
value: {type: String, default: ""},
placeholder: {type: String, default: "You Should Add Placeholder Text"},
help: {type: String, default: undefined},
subtitle: {type: String, default: undefined},
disabled: {type: Boolean, default: false},
optional: {type: Boolean, default: false},
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
data() {
return {
new_value: undefined,
}
},
mounted() {
this.new_value = this.value
},
watch: {
new_value: function () {
this.$root.$emit("change", this.field, this.new_value)
},
},
methods: {},
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<div>
<b-form-group v-bind:label="label" class="mb-3">
<b-form-input v-model="new_value" type="text" :placeholder="placeholder"></b-form-input>
<b-form-group v-bind:label="field_label" class="mb-3">
<b-form-input v-model="new_value" type="text" :placeholder="placeholder" :disabled="disabled"></b-form-input>
<em v-if="help" class="small text-muted">{{ help }}</em>
<small v-if="subtitle" class="text-muted">{{ subtitle }}</small>
</b-form-group>
@ -18,12 +18,23 @@ export default {
placeholder: { type: String, default: "You Should Add Placeholder Text" },
help: { type: String, default: undefined },
subtitle: { type: String, default: undefined },
disabled: { type: Boolean, default: false },
optional: {type: Boolean, default: false},
},
data() {
return {
new_value: undefined,
}
},
computed: {
field_label: function () {
if (this.optional) {
return this.label
} else {
return this.label + '*'
}
}
},
mounted() {
this.new_value = this.value
},

View File

@ -0,0 +1,94 @@
<template>
<div>
<beta-warning></beta-warning>
<div v-if="metadata !== undefined">
{{ $t('Data_Import_Info') }}
<a href="https://github.com/TandoorRecipes/open-tandoor-data" target="_blank" rel="noreferrer nofollow">{{$t('Learn_More')}}</a>
<select class="form-control" v-model="selected_version">
<option v-for="v in metadata.versions" v-bind:key="v">{{ v }}</option>
</select>
<b-checkbox v-model="update_existing" class="mt-1">{{ $t('Update_Existing_Data') }}</b-checkbox>
<b-checkbox v-model="use_metric" class="mt-1">{{ $t('Use_Metric') }}</b-checkbox>
<div v-if="selected_version !== undefined" class="mt-3">
<table class="table">
<tr>
<th>{{ $t('Datatype') }}</th>
<th>{{ $t('Number of Objects') }}</th>
<th>{{ $t('Imported') }}</th>
</tr>
<tr v-for="d in metadata.datatypes" v-bind:key="d">
<td>{{ $t(d.charAt(0).toUpperCase() + d.slice(1)) }}</td>
<td>{{ metadata[selected_version][d] }}</td>
<td>
<template v-if="import_count !== undefined">{{ import_count[d] }}</template>
</td>
</tr>
</table>
<button class="btn btn-success" @click="doImport">{{ $t('Import') }}</button>
</div>
</div>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {ApiMixin, resolveDjangoUrl, StandardToasts} from "@/utils/utils";
import axios from "axios";
import BetaWarning from "@/components/BetaWarning.vue";
Vue.use(BootstrapVue)
export default {
name: "OpenDataImportComponent",
mixins: [ApiMixin],
components: {BetaWarning},
data() {
return {
metadata: undefined,
selected_version: undefined,
update_existing: true,
use_metric: true,
import_count: undefined,
}
},
mounted() {
this.$i18n.locale = window.CUSTOM_LOCALE
axios.get(resolveDjangoUrl('api_import_open_data')).then(r => {
this.metadata = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
},
methods: {
doImport: function () {
axios.post(resolveDjangoUrl('api_import_open_data'), {
'selected_version': this.selected_version,
'selected_datatypes': this.metadata.datatypes,
'update_existing': this.update_existing,
'use_metric': this.use_metric,
}).then(r => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_CREATE)
this.import_count = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err)
})
},
},
}
</script>

View File

@ -1,28 +1,28 @@
<template>
<div>
<iframe :src="pdfUrl" width="100%" height="700px" style="border: none;"></iframe>
</div>
<div>
<iframe :src="pdfUrl" width="100%" height="700px" style="border: none;"></iframe>
</div>
</template>
<script>
import {resolveDjangoUrl, ResolveUrlMixin} from "@/utils/utils";
import {resolveDjangoStatic, resolveDjangoUrl, ResolveUrlMixin} from "@/utils/utils";
export default {
name: 'PdfViewer',
mixins: [
ResolveUrlMixin
],
props: {
recipe: Object,
},
computed: {
pdfUrl: function() {
return '/static/pdfjs/viewer.html?file=' + resolveDjangoUrl('api_get_recipe_file', (this.recipe.id))
}
},
name: 'PdfViewer',
mixins: [
ResolveUrlMixin
],
props: {
recipe: Object,
},
computed: {
pdfUrl: function () {
return resolveDjangoStatic('pdfjs/viewer.html?file=' + resolveDjangoUrl('api_get_recipe_file', (this.recipe.id)))
}
},
}
</script>

View File

@ -0,0 +1,196 @@
<template>
<div>
<div class="card p-4 pb-2" v-if="recipe !== undefined && property_list.length > 0">
<b-row>
<b-col>
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
</b-col>
<b-col class="text-right">
<div v-if="hasRecipeProperties && hasFoodProperties">
<span v-if="!show_recipe_properties">{{ $t('Food') }} </span>
<span v-if="show_recipe_properties">{{ $t('Recipe') }} </span>
<a href="#" @click="show_recipe_properties = !show_recipe_properties">
<i class="fas fa-toggle-on" v-if="!show_recipe_properties"></i>
<i class="fas fa-toggle-off" v-if="show_recipe_properties"></i>
</a>
</div>
</b-col>
</b-row>
<table class="table table-bordered table-sm">
<tr >
<td style="border-top: none"></td>
<td class="text-right" style="border-top: none">{{ $t('per_serving') }}</td>
<td class="text-right" style="border-top: none">{{ $t('total') }}</td>
<td style="border-top: none"></td>
</tr>
<tr v-for="p in property_list" v-bind:key="`id_${p.id}`">
<td>
{{ p.name }}
</td>
<td class="text-right">{{ roundDecimals(p.property_amount_per_serving) }}</td>
<td class="text-right">{{ roundDecimals(p.property_amount_total) }}</td>
<td class=""> {{ p.unit }}</td>
<td class="align-middle text-center" v-if="!show_recipe_properties">
<a href="#" @click="selected_property = p">
<i v-if="p.missing_value" class="text-warning fas fa-exclamation-triangle"></i>
<i v-if="!p.missing_value" class="text-muted fas fa-info-circle"></i>
</a>
</td>
</tr>
</table>
</div>
<b-modal id="id_modal_property_overview" :title="selected_property.name" v-model="show_modal" v-if="selected_property !== undefined"
@hidden="selected_property = undefined">
<template v-if="selected_property !== undefined">
{{ selected_property.description }}
<table class="table table-bordered">
<tr v-for="f in selected_property.food_values"
v-bind:key="`id_${selected_property.id}_food_${f.id}`">
<td><a href="#" @click="openFoodEditModal(f)">{{ f.food }}</a></td>
<td>{{ f.value }} {{ selected_property.unit }}</td>
</tr>
</table>
</template>
</b-modal>
<generic-modal-form
:model="Models.FOOD"
:action="Actions.UPDATE"
:item1="selected_food"
:show="show_food_edit_modal"
@hidden="foodEditorHidden"
>
</generic-modal-form>
</div>
</template>
<script>
import {ApiMixin, roundDecimals, StandardToasts} from "@/utils/utils";
import GenericModalForm from "@/components/Modals/GenericModalForm.vue";
import {ApiApiFactory} from "@/utils/openapi/api";
export default {
name: "PropertyViewComponent",
mixins: [ApiMixin],
components: {GenericModalForm},
props: {
recipe: Object,
servings: Number,
},
data() {
return {
selected_property: undefined,
selected_food: undefined,
show_food_edit_modal: false,
show_recipe_properties: false,
}
},
computed: {
show_modal: function () {
return this.selected_property !== undefined
},
hasRecipeProperties: function () {
return this.recipe.properties.length !== 0
},
hasFoodProperties: function () {
let has_food_properties = false
for (const [key, fp] of Object.entries(this.recipe.food_properties)) {
if (fp.total_value !== 0) {
has_food_properties = true
}
}
return has_food_properties
},
property_list: function () {
let pt_list = []
if (this.show_recipe_properties) {
this.recipe.properties.forEach(rp => {
pt_list.push(
{
'id': rp.property_type.id,
'name': rp.property_type.name,
'description': rp.property_type.description,
'icon': rp.property_type.icon,
'food_values': [],
'property_amount_per_serving': rp.property_amount,
'property_amount_total': rp.property_amount * this.recipe.servings * (this.servings / this.recipe.servings),
'missing_value': false,
'unit': rp.property_type.unit,
'type': rp.property_type,
}
)
})
} else {
for (const [key, fp] of Object.entries(this.recipe.food_properties)) {
pt_list.push(
{
'id': fp.id,
'name': fp.name,
'description': fp.description,
'icon': fp.icon,
'food_values': fp.food_values,
'property_amount_per_serving': fp.total_value / this.recipe.servings,
'property_amount_total': fp.total_value * (this.servings / this.recipe.servings),
'missing_value': fp.missing_value,
'unit': fp.unit,
'type': fp,
}
)
}
}
function compare(a,b){
if(a.type.order > b.type.order){
return 1
}
if(a.type.order < b.type.order){
return -1
}
return 0
}
return pt_list.sort(compare)
}
},
mounted() {
if (this.hasRecipeProperties && !this.hasFoodProperties) {
this.show_recipe_properties = true
}
},
methods: {
roundDecimals,
openFoodEditModal: function (food) {
console.log(food)
let apiClient = ApiApiFactory()
apiClient.retrieveFood(food.id).then(r => {
this.selected_food = r.data;
this.show_food_edit_modal = true
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
},
foodEditorHidden: function () {
this.show_food_edit_modal = false;
this.$emit("foodUpdated", "")
}
},
}
</script>
<style scoped>
</style>

View File

@ -21,7 +21,7 @@
<template v-else>
<b-card no-body v-hover v-if="recipe" style="height: 100%">
<a :href="this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null">
<a :href="recipe_link">
<div class="content">
<div class="content-overlay" v-if="recipe.description !== null && recipe.description !== ''"></div>
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src="recipe_image"
@ -35,12 +35,12 @@
<div class="card-img-overlay d-flex flex-column justify-content-left float-left text-left pt-2" style="width:40%"
v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0 && recipe.working_time !== undefined">
<i
class="fa fa-clock"></i> {{ working_time }}
</b-badge>
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"
v-if="recipe.waiting_time !== 0">
v-if="recipe.waiting_time !== 0 && recipe.waiting_time !== undefined">
<i class="fa fa-pause"></i> {{ waiting_time }}
</b-badge>
</div>
@ -50,7 +50,7 @@
<b-card-body class="p-2 pl-3 pr-3">
<div class="d-flex flex-row">
<div class="flex-grow-1">
<a :href="this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null" class="text-body font-weight-bold two-row-text">
<a :href="recipe_link" class="text-body font-weight-bold two-row-text">
<template v-if="recipe !== null">{{ recipe.name }}</template>
<template v-else>{{ meal_plan.title }}</template>
</a>
@ -58,7 +58,7 @@
<div class="justify-content-end">
<recipe-context-menu :recipe="recipe" class="justify-content-end float-right align-items-end pr-0"
:disabled_options="context_disabled_options"
v-if="recipe !== null"></recipe-context-menu>
v-if="recipe !== null && show_context_menu"></recipe-context-menu>
</div>
</div>
@ -71,7 +71,7 @@
<p class="mt-1 mb-1">
<last-cooked :recipe="recipe"></last-cooked>
<keywords-component :recipe="recipe" :limit="3"
<keywords-component :recipe="recipe" :limit="3" :enable_keyword_links="enable_keyword_links"
style="margin-top: 4px; position: relative; z-index: 3;"></keywords-component>
</p>
<transition name="fade" mode="in-out">
@ -89,7 +89,7 @@
</div>
</transition>
<b-badge pill variant="info" v-if="!recipe.internal">{{ $t("External") }}</b-badge>
<b-badge pill variant="info" v-if="recipe.internal !== undefined && !recipe.internal">{{ $t("External") }}</b-badge>
</template>
</b-card-text>
@ -152,6 +152,8 @@ export default {
detailed: {type: Boolean, default: true},
show_context_menu: {type: Boolean, default: true},
context_disabled_options: Object,
open_recipe_on_click: {type: Boolean, default: true},
enable_keyword_links: {type: Boolean, default: true},
},
data() {
return {
@ -178,6 +180,13 @@ export default {
waiting_time: function () {
return calculateHourMinuteSplit(this.recipe.waiting_time)
},
recipe_link: function (){
if(this.open_recipe_on_click){
return this.recipe.id !== undefined ? resolveDjangoUrl('view_recipe', this.recipe.id) : null
} else {
return "#"
}
}
},
methods: {},
directives: {

View File

@ -184,7 +184,7 @@ export default {
localStorage.setItem("pinned_recipes", JSON.stringify(pinnedRecipes))
},
saveMealPlan: function (entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
entry.from_date = moment(entry.from_date).format("YYYY-MM-DD")
let reviewshopping = entry.addshopping && entry.reviewshopping
entry.addshopping = entry.addshopping && !entry.reviewshopping
@ -208,7 +208,7 @@ export default {
createMealPlan(data) {
this.entryEditing = this.options.entryEditing
this.entryEditing.recipe = this.recipe
this.entryEditing.date = moment(new Date()).format("YYYY-MM-DD")
this.entryEditing.from_date = moment(new Date()).format("YYYY-MM-DD")
this.$nextTick(function () {
this.$bvModal.show(`modal-meal-plan_${this.modal_id}`)
})

View File

@ -0,0 +1,370 @@
<template>
<div>
<template v-if="loading">
<loading-spinner></loading-spinner>
</template>
<div v-if="!loading" style="padding-bottom: 60px">
<RecipeSwitcher ref="ref_recipe_switcher" @switch="quickSwitch($event)" v-if="show_recipe_switcher"/>
<div class="row">
<div class="col-12" style="text-align: center">
<h3>{{ recipe.name }}</h3>
</div>
</div>
<div class="row text-center">
<div class="col col-md-12">
<recipe-rating :recipe="recipe"></recipe-rating>
<last-cooked :recipe="recipe" class="mt-2"></last-cooked>
</div>
</div>
<div class="my-auto">
<div class="col-12" style="text-align: center">
<i>{{ recipe.description }}</i>
</div>
</div>
<div style="text-align: center">
<keywords-component :recipe="recipe" :enable_keyword_links="enable_keyword_links"></keywords-component>
</div>
<hr/>
<div class="row align-items-center">
<div class="col col-md-3">
<div class="d-flex">
<div class="my-auto mr-1">
<i class="fas fa-fw fa-user-clock fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<span class="text-primary"><b>{{ $t("Preparation") }}</b></span><br/>
{{ working_time }}
</div>
</div>
</div>
<div class="col col-md-3">
<div class="row d-flex">
<div class="my-auto mr-1">
<i class="far fa-fw fa-clock fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<span class="text-primary"><b>{{ $t("Waiting") }}</b></span><br/>
{{ waiting_time }}
</div>
</div>
</div>
<div class="col col-md-4 col-10 mt-2 mt-md-0">
<div class="d-flex">
<div class="my-auto mr-1">
<i class="fas fa-fw fa-pizza-slice fa-2x text-primary"></i>
</div>
<div class="my-auto mr-1">
<CustomInputSpinButton v-model.number="servings"/>
</div>
<div class="my-auto mr-1">
<span class="text-primary">
<b>
<template v-if="recipe.servings_text === ''">{{ $t("Servings") }}</template>
<template v-else>{{ recipe.servings_text }}</template>
</b>
</span>
</div>
</div>
</div>
<div class="col col-md-2 col-2 mt-2 mt-md-0 text-right">
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"
:disabled_options="{print:false}" v-if="show_context_menu"></recipe-context-menu>
</div>
</div>
<hr/>
<div class="row">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2"
v-if="recipe && ingredient_count > 0 && (recipe.show_ingredient_overview || recipe.steps.length < 2)">
<ingredients-card
:recipe="recipe.id"
:steps="recipe.steps"
:ingredient_factor="ingredient_factor"
:servings="servings"
:header="true"
id="ingredient_container"
@checked-state-changed="updateIngredientCheckedState"
@change-servings="servings = $event"
/>
</div>
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
<div class="row">
<div class="col-12">
<img class="img img-fluid rounded" :src="recipe.image" :alt="$t('Recipe_Image')"
v-if="recipe.image !== null" @load="onImgLoad"
:style="{ 'max-height': ingredient_height }"/>
</div>
</div>
</div>
</div>
<template v-if="!recipe.internal">
<div v-if="recipe.file_path.includes('.pdf')">
<PdfViewer :recipe="recipe"></PdfViewer>
</div>
<div
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg') || recipe.file_path.includes('.gif')">
<ImageViewer :recipe="recipe"></ImageViewer>
</div>
</template>
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
<step-component
:recipe="recipe"
:step="s"
:ingredient_factor="ingredient_factor"
:index="index"
:start_time="start_time"
@update-start-time="updateStartTime"
@checked-state-changed="updateIngredientCheckedState"
></step-component>
</div>
<div v-if="recipe.source_url !== null">
<h6 class="d-print-none"><i class="fas fa-file-import"></i> {{ $t("Imported_From") }}</h6>
<span class="text-muted mt-1"><a style="overflow-wrap: break-word;"
:href="recipe.source_url">{{ recipe.source_url }}</a></span>
</div>
<div class="row" style="margin-top: 2vh; ">
<div class="col-lg-6 offset-lg-3 col-12">
<property-view-component :recipe="recipe" :servings="servings" @foodUpdated="loadRecipe(recipe.id)"></property-view-component>
</div>
</div>
</div>
<add-recipe-to-book :recipe="recipe"></add-recipe-to-book>
<div class="row text-center d-print-none" style="margin-top: 3vh; margin-bottom: 3vh"
v-if="share_uid !== 'None' && !loading">
<div class="col col-md-12">
<import-tandoor></import-tandoor>
<br/>
<a :href="resolveDjangoUrl('view_report_share_abuse', share_uid)" class="mt-3">{{ $t("Report Abuse") }}</a>
</div>
</div>
</div>
</template>
<script>
import Vue from "vue"
import {BootstrapVue} from "bootstrap-vue"
import "bootstrap-vue/dist/bootstrap-vue.css"
import {apiLoadRecipe} from "@/utils/api"
import RecipeContextMenu from "@/components/RecipeContextMenu"
import {ResolveUrlMixin, ToastMixin, calculateHourMinuteSplit} from "@/utils/utils"
import PdfViewer from "@/components/PdfViewer"
import ImageViewer from "@/components/ImageViewer"
import moment from "moment"
import LoadingSpinner from "@/components/LoadingSpinner"
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook"
import RecipeRating from "@/components/RecipeRating"
import LastCooked from "@/components/LastCooked"
import IngredientsCard from "@/components/IngredientsCard"
import StepComponent from "@/components/StepComponent"
import KeywordsComponent from "@/components/KeywordsComponent"
import RecipeSwitcher from "@/components/Buttons/RecipeSwitcher"
import CustomInputSpinButton from "@/components/CustomInputSpinButton"
import {ApiApiFactory} from "@/utils/openapi/api";
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
import PropertyViewComponent from "@/components/PropertyViewComponent.vue";
Vue.prototype.moment = moment
Vue.use(BootstrapVue)
export default {
name: "RecipeView",
mixins: [ResolveUrlMixin, ToastMixin],
components: {
ImportTandoor,
LastCooked,
RecipeRating,
PdfViewer,
ImageViewer,
IngredientsCard,
StepComponent,
RecipeContextMenu,
KeywordsComponent,
LoadingSpinner,
AddRecipeToBook,
RecipeSwitcher,
CustomInputSpinButton,
PropertyViewComponent,
},
computed: {
ingredient_factor: function () {
return this.servings / this.recipe.servings
},
ingredient_count() {
return this.recipe?.steps.map((x) => x.ingredients).flat().length
},
working_time: function () {
return calculateHourMinuteSplit(this.recipe.working_time)
},
waiting_time: function () {
return calculateHourMinuteSplit(this.recipe.waiting_time)
},
},
data() {
return {
loading: true,
recipe: undefined,
rootrecipe: undefined,
servings: 1,
servings_cache: {},
start_time: "",
share_uid: window.SHARE_UID,
wake_lock: null,
ingredient_height: '250',
}
},
props: {
recipe_id: Number,
recipe_obj: {type: Object, default: null},
show_context_menu: {type: Boolean, default: true},
enable_keyword_links: {type: Boolean, default: true},
show_recipe_switcher: {type: Boolean, default: true},
//show_comments: {type: Boolean, default: true},
},
watch: {
servings(newVal, oldVal) {
this.servings_cache[this.recipe.id] = this.servings
},
},
mounted() {
if (this.recipe_obj !== null) {
this.recipe = this.rootrecipe = this.recipe_obj
this.prepareView()
} else {
this.loadRecipe(this.recipe_id)
}
this.$i18n.locale = window.CUSTOM_LOCALE
this.requestWakeLock()
window.addEventListener('resize', this.handleResize);
},
beforeUnmount() {
this.destroyWakeLock()
},
methods: {
requestWakeLock: async function () {
if ('wakeLock' in navigator) {
try {
this.wake_lock = await navigator.wakeLock.request('screen')
document.addEventListener('visibilitychange', this.visibilityChange)
} catch (err) {
console.log(err)
}
}
},
handleResize: function () {
if (document.getElementById('nutrition_container') !== null) {
this.ingredient_height = document.getElementById('ingredient_container').clientHeight - document.getElementById('nutrition_container').clientHeight
} else {
this.ingredient_height = document.getElementById('ingredient_container').clientHeight
}
},
destroyWakeLock: function () {
if (this.wake_lock != null) {
this.wake_lock.release()
.then(() => {
this.wake_lock = null
});
}
document.removeEventListener('visibilitychange', this.visibilityChange)
},
visibilityChange: async function () {
if (this.wake_lock != null && document.visibilityState === 'visible') {
await this.requestWakeLock()
}
},
loadRecipe: function (recipe_id) {
apiLoadRecipe(recipe_id).then((recipe) => {
this.recipe = this.rootrecipe = recipe
this.prepareView()
})
},
prepareView: function () {
let total_time = 0
for (let step of this.recipe.steps) {
for (let ingredient of step.ingredients) {
this.$set(ingredient, "checked", false)
}
step.time_offset = total_time
total_time += step.time
}
// set start time only if there are any steps with timers (otherwise no timers are rendered)
if (total_time > 0) {
this.start_time = moment().format("yyyy-MM-DDTHH:mm")
}
if (this.recipe.image === null) this.printReady()
this.servings = this.servings_cache[this.rootrecipe.id] = this.recipe.servings
this.loading = false
setTimeout(() => {
this.handleResize()
}, 100)
},
updateStartTime: function (e) {
this.start_time = e
},
updateIngredientCheckedState: function (e) {
for (let step of this.recipe.steps) {
for (let ingredient of step.ingredients) {
if (ingredient.id === e.id) {
this.$set(ingredient, "checked", !ingredient.checked)
}
}
}
},
quickSwitch: function (e) {
if (e === -1) {
this.recipe = this.rootrecipe
this.servings = this.servings_cache[this.rootrecipe?.id ?? 1]
} else {
this.recipe = e
this.servings = this.servings_cache?.[e.id] ?? e.servings
}
},
printReady: function () {
const template = document.createElement("template");
template.id = "printReady";
document.body.appendChild(template);
},
onImgLoad: function () {
this.printReady()
},
},
}
</script>
<style>
#app > div > div {
break-inside: avoid;
}
</style>

View File

@ -31,6 +31,12 @@
</b-form-checkbox>
</b-form-group>
<b-form-group :description="$t('show_step_ingredients_setting_help')">
<b-form-checkbox v-model="user_preferences.show_step_ingredients" @change="updateSettings(false);">
{{ $t('show_step_ingredients_setting') }}
</b-form-checkbox>
</b-form-group>
<hr/>
@ -50,6 +56,7 @@
<b-form-select-option value="DARKLY">Darkly</b-form-select-option>
<b-form-select-option value="FLATLY">Flatly</b-form-select-option>
<b-form-select-option value="SUPERHERO">Superhero</b-form-select-option>
<b-form-select-option value="TANDOOR_DARK">Tandoor Dark (INCOMPLETE)</b-form-select-option>
</b-form-select>
</b-form-group>

View File

@ -11,6 +11,63 @@
:placeholder="$t('User')"
></generic-multiselect>
</b-form-group>
<hr/>
<b-form v-if="settings">
<b-form-group id="UomInput" :label="$t('Period')" :description="$t('Plan_Period_To_Show')"
label-for="UomInput">
<b-form-select id="UomInput" v-model="settings.displayPeriodUom"
:options="calendar_options.displayPeriodUom"></b-form-select>
</b-form-group>
<b-form-group id="PeriodInput" :label="$t('Periods')"
:description="$t('Plan_Show_How_Many_Periods')" label-for="PeriodInput">
<b-form-select id="PeriodInput" v-model="settings.displayPeriodCount"
:options="calendar_options.displayPeriodCount"></b-form-select>
</b-form-group>
<b-form-group id="DaysInput" :label="$t('Starting_Day')" :description="$t('Starting_Day')"
label-for="DaysInput">
<b-form-select id="DaysInput" v-model="settings.startingDayOfWeek"
:options="dayNames()"></b-form-select>
</b-form-group>
<b-form-group id="WeekNumInput" :label="$t('Week_Numbers')">
<b-form-checkbox v-model="settings.displayWeekNumbers" name="week_num">
{{ $t("Show_Week_Numbers") }}
</b-form-checkbox>
</b-form-group>
</b-form>
<hr/>
<h5>{{ $t("Meal_Types") }}
<button type="button" class="btn btn-success shadow-none float-right" @click="generic_action = Actions.CREATE;"><i class="fas fa-plus"></i></button>
</h5>
<draggable :list="meal_types" group="meal_types" :empty-insert-threshold="10" class="mt-4"
@sort="sortMealTypes()" ghost-class="ghost" handle=".handle">
<b-list-group-item v-for="mt in meal_types" v-bind:key="mt.id">
<button type="button" class="btn handle shadow-none"><i class="fas fa-arrows-alt-v"></i></button>
<b-badge :style="{'background-color': mt.color}"><i class="fas fa-palette"></i> </b-badge>
<span> {{ mt.name }} </span>
<b-badge v-if="mt.default">{{ $t('Default') }}</b-badge>
<div class="btn-group float-right">
<button type="button" class="btn btn-primary shadow-none" @click="generic_action = Actions.UPDATE; editing_meal_type=mt;"><i class="fas fa-edit"></i></button>
<button type="button" class="btn btn-danger shadow-none" @click="generic_action = Actions.DELETE; editing_meal_type=mt;"><i class="fas fa-trash-alt"></i></button>
</div>
</b-list-group-item>
</draggable>
<b-list-group>
</b-list-group>
<generic-modal-form :model="Models.MEAL_TYPE" :action="generic_action" :show="generic_action !== null"
:item1="editing_meal_type"
@finish-action="finishGenericAction"/>
</div>
</template>
@ -20,16 +77,18 @@ import {ApiMixin, StandardToasts} from "@/utils/utils";
import axios from "axios";
import GenericMultiselect from "@/components/GenericMultiselect";
import {useMealPlanStore} from "@/stores/MealPlanStore";
import {CalendarMathMixin} from "vue-simple-calendar/src/components/bundle";
import draggable from "vuedraggable"
import GenericModalForm from "@/components/Modals/GenericModalForm.vue";
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
let SETTINGS_COOKIE_NAME = "mealplan_settings"
export default {
name: "MealPlanSettingsComponent",
mixins: [ApiMixin],
components: {GenericMultiselect},
mixins: [ApiMixin, CalendarMathMixin],
components: {GenericModalForm, draggable, GenericMultiselect},
props: {
user_id: Number,
},
@ -37,12 +96,38 @@ export default {
return {
user_preferences: undefined,
languages: [],
settings: undefined,
calendar_options: {
displayPeriodUom: [
{text: this.$t("Week"), value: "week"},
{text: this.$t("Month"), value: "month",},
{text: this.$t("Year"), value: "year"},
],
displayPeriodCount: [1, 2, 3, 4],
},
meal_types: [],
generic_action: null,
editing_meal_type: null,
}
},
watch: {
settings: {
handler() {
useMealPlanStore().updateClientSettings(this.settings)
},
deep: true,
},
},
mounted() {
this.user_preferences = this.preferences
this.languages = window.AVAILABLE_LANGUAGES
this.loadSettings()
this.settings = useMealPlanStore().client_settings
this.loadMealTypes()
},
methods: {
loadSettings: function () {
@ -64,6 +149,43 @@ export default {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
},
dayNames: function () {
let options = []
this.getFormattedWeekdayNames(this.getDefaultBrowserLocale(), "long", 0).forEach((day, index) => {
options.push({text: day, value: index})
})
return options
},
loadMealTypes: function () {
let apiClient = new ApiApiFactory()
apiClient.listMealTypes().then(result => {
this.meal_types = result.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
})
},
sortMealTypes() {
this.meal_types.forEach(function (element, index) {
element.order = index
})
this.meal_types.forEach((meal_type) => {
let apiClient = new ApiApiFactory()
apiClient.updateMealType(meal_type.id, meal_type).then((e) => {
}).catch((err) => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
})
},
finishGenericAction: function (e) {
if (e !== 'cancel') {
this.loadMealTypes()
}
this.editing_meal_type = null;
this.generic_action = null;
}
}
}
</script>

View File

@ -33,7 +33,7 @@
<div class="row">
<!-- ingredients table -->
<div class="col col-md-4"
v-if="step.ingredients.length > 0 && (recipe.steps.length > 1 || force_ingredients)">
v-if="step.show_ingredients_table && step.ingredients.length > 0 && (recipe.steps.length > 1 || force_ingredients)">
<table class="table table-sm">
<ingredients-card :steps="[step]" :ingredient_factor="ingredient_factor"
@checked-state-changed="$emit('checked-state-changed', $event)"/>
@ -124,10 +124,7 @@
</template>
<script>
import {calculateAmount} from "@/utils/utils"
import {GettextMixin} from "@/utils/utils"
import {calculateAmount, GettextMixin, getUserPreference} from "@/utils/utils"
import CompileComponent from "@/components/CompileComponent"
import IngredientsCard from "@/components/IngredientsCard"
import Vue from "vue"

View File

@ -4,6 +4,8 @@ import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
function loadLocaleMessages () {
const start_time = Date.now();
console.log('started loading locale messages')
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
@ -13,6 +15,7 @@ function loadLocaleMessages () {
messages[locale] = locales(key)
}
})
console.log('finished loading messages in ', Date.now() - start_time, ' ms')
return messages
}

View File

@ -16,7 +16,6 @@
"file_upload_disabled": "",
"warning_space_delete": "",
"food_inherit_info": "",
"facet_count_info": "",
"step_time_minutes": "",
"confirm_delete": "",
"import_running": "",

View File

@ -1,482 +1,498 @@
{
"warning_feature_beta": "",
"err_fetching_resource": "",
"err_creating_resource": "",
"err_updating_resource": "",
"err_deleting_resource": "",
"err_deleting_protected_resource": "",
"err_moving_resource": "",
"err_merging_resource": "",
"success_fetching_resource": "",
"success_creating_resource": "",
"success_updating_resource": "",
"success_deleting_resource": "",
"success_moving_resource": "",
"success_merging_resource": "",
"file_upload_disabled": "",
"warning_space_delete": "",
"food_inherit_info": "",
"facet_count_info": "",
"step_time_minutes": "",
"confirm_delete": "",
"import_running": "",
"all_fields_optional": "",
"convert_internal": "",
"show_only_internal": "",
"show_split_screen": "",
"warning_feature_beta": "Tato funkce je momentálně ve fázi Beta (testování). Očekávejte, prosím, chyby. V budoucnosti může dojít i ke ztrátě dat.",
"err_fetching_resource": "Během načítání došlo k chybě!",
"err_creating_resource": "Během vytváření došlo k chybě!",
"err_updating_resource": "Během úprav došlo k chybě!",
"err_deleting_resource": "Během mazání došlo k chybě!",
"err_deleting_protected_resource": "Položka, kterou chcete smazat, je stále používána a nemůže být odstraněna.",
"err_moving_resource": "Během přesunu došlo k chybě!",
"err_merging_resource": "Během slučování došlo k chybě!",
"success_fetching_resource": "Úspěšně načteno!",
"success_creating_resource": "Úspěšně vytvořeno!",
"success_updating_resource": "Úspěšně upraveno!",
"success_deleting_resource": "Úspěšně smazáno!",
"success_moving_resource": "Úspěšně přesunuto!",
"success_merging_resource": "Úspěšně sloučeno!",
"file_upload_disabled": "Nahrávání souborů není povoleno pro Váš prostor.",
"warning_space_delete": "Můžete smazat váš prostor včetně všech receptů, nákupních seznamů, jídelníčků a všeho ostatního, co jste vytvořili. Tuto akci nemůžete vzít zpět! Jste si jisti, že chcete pokračovat?",
"food_inherit_info": "Pole potravin, která budou standardně zděděna.",
"step_time_minutes": "Nastavte čas v minutách",
"confirm_delete": "Jste si jisti že chcete odstranit tento {objekt}?",
"import_running": "Probíhá import, čekejte prosím!",
"all_fields_optional": "Všechna pole jsou nepviná a mohou být ponechána prázdná.",
"convert_internal": "Převést na interní recept",
"show_only_internal": "Zobrazit pouze interní recepty",
"show_split_screen": "Rozdělené zobrazení",
"Log_Recipe_Cooking": "",
"External_Recipe_Image": "",
"Add_to_Shopping": "",
"Add_to_Plan": "",
"Step_start_time": "",
"Sort_by_new": "",
"Table_of_Contents": "",
"Recipes_per_page": "",
"Show_as_header": "",
"Hide_as_header": "",
"Add_nutrition_recipe": "",
"Remove_nutrition_recipe": "",
"External_Recipe_Image": "Externí obrázek receptu",
"Add_to_Shopping": "Přidat k nákupu",
"Add_to_Plan": "Přidat do jídelníčku",
"Step_start_time": "Nastav počáteční čas",
"Sort_by_new": "Seřadit od nejnovějšího",
"Table_of_Contents": "Obsah",
"Recipes_per_page": "Receptů na stránku",
"Show_as_header": "Nastav jako nadpis",
"Hide_as_header": "Skryj jako nadpis",
"Add_nutrition_recipe": "Přidat nutriční hodnoty",
"Remove_nutrition_recipe": "Smazat nutriční hodnoty",
"Copy_template_reference": "",
"Save_and_View": "",
"Manage_Books": "",
"Meal_Plan": "",
"Select_Book": "",
"Select_File": "",
"Recipe_Image": "",
"Import_finished": "",
"View_Recipes": "",
"Save_and_View": "Uložit & Zobrazit",
"Manage_Books": "Spravovat kuchařky",
"Meal_Plan": "Jídelníček",
"Select_Book": "Vyber kuchařku",
"Select_File": "Vybrat soubor",
"Recipe_Image": "Obrázek k receptu",
"Import_finished": "Import dokončen",
"View_Recipes": "Zobrazit recepty",
"Log_Cooking": "",
"New_Recipe": "",
"Url_Import": "",
"Reset_Search": "",
"Recently_Viewed": "",
"Load_More": "",
"New_Keyword": "",
"Delete_Keyword": "",
"Edit_Keyword": "",
"Edit_Recipe": "",
"Move_Keyword": "",
"Merge_Keyword": "",
"Hide_Keywords": "",
"Hide_Recipes": "",
"Move_Up": "",
"Move_Down": "",
"Step_Name": "",
"Step_Type": "",
"Make_Header": "",
"Make_Ingredient": "",
"Amount": "",
"Enable_Amount": "",
"Disable_Amount": "",
"Ingredient Editor": "",
"Description_Replace": "",
"Instruction_Replace": "",
"Auto_Sort": "",
"Auto_Sort_Help": "",
"Private_Recipe": "",
"Private_Recipe_Help": "",
"reusable_help_text": "",
"Add_Step": "",
"Keywords": "",
"Books": "",
"Proteins": "",
"Fats": "",
"Carbohydrates": "",
"Calories": "",
"Energy": "",
"New_Recipe": "Nový recept",
"Url_Import": "Import pomocí URL odkazu",
"Reset_Search": "Zrušit filtry vyhledávání",
"Recently_Viewed": "Naposledy prohlížené",
"Load_More": "Načíst další",
"New_Keyword": "Nové klíčové slovo",
"Delete_Keyword": "Smazat klíčové slovo",
"Edit_Keyword": "Upravit klíčové slovo",
"Edit_Recipe": "Upravit recept",
"Move_Keyword": "Přesunout klíčové slovo",
"Merge_Keyword": "Sloučit klíčové slovo",
"Hide_Keywords": "Skrýt klíčové slovo",
"Hide_Recipes": "Skrýt recept",
"Move_Up": "Nahoru",
"Move_Down": "Dolů",
"Step_Name": "Název kroku",
"Step_Type": "Druh kroku",
"Make_Header": "Použij jako nadpis",
"Make_Ingredient": "Použij jako ingredienci",
"Amount": "Množství",
"Enable_Amount": "Zobrazit množství",
"Disable_Amount": "Skrýt množství",
"Ingredient Editor": "Editace ingrediencí",
"Description_Replace": "Nahraď popis",
"Instruction_Replace": "Nahraď instrukce",
"Auto_Sort": "Automatické řazení",
"Auto_Sort_Help": "Přiřadit všechny ingredience k nejlépe vyhovujícímu kroku.",
"Private_Recipe": "Soukromý recept",
"Private_Recipe_Help": "Recept můžete zobrazit pouze vy a lidé, se kterými jej sdílíte.",
"reusable_help_text": "Má-li pozvánka platit pro více než jednoho uživatele.",
"Add_Step": "Přidat krok",
"Keywords": "Klíčová slova",
"Books": "Kuchařky",
"Proteins": "Proteiny",
"Fats": "Tuky",
"Carbohydrates": "Sacharidy",
"Calories": "Kalorie",
"Energy": "Energie",
"Nutrition": "",
"Date": "",
"Share": "",
"Automation": "",
"Parameter": "",
"Export": "",
"Copy": "",
"Rating": "",
"Close": "",
"Cancel": "",
"Link": "",
"Add": "",
"New": "",
"Note": "",
"Success": "",
"Failure": "",
"Protected": "",
"Ingredients": "",
"Supermarket": "",
"Categories": "",
"Category": "",
"Selected": "",
"min": "",
"Servings": "",
"Waiting": "",
"Preparation": "",
"External": "",
"Size": "",
"Files": "",
"File": "",
"Edit": "",
"Image": "",
"Delete": "",
"Open": "",
"Ok": "",
"Save": "",
"Step": "",
"Search": "",
"Import": "",
"Print": "",
"Settings": "",
"or": "",
"and": "",
"Information": "",
"Download": "",
"Create": "",
"Search Settings": "",
"View": "",
"Recipes": "",
"Move": "",
"Merge": "",
"Parent": "",
"Copy Link": "",
"Copy Token": "",
"delete_confirmation": "",
"move_confirmation": "",
"merge_confirmation": "",
"create_rule": "",
"move_selection": "",
"merge_selection": "",
"Root": "",
"Ignore_Shopping": "",
"Shopping_Category": "",
"Shopping_Categories": "",
"Edit_Food": "",
"Move_Food": "",
"New_Food": "",
"Hide_Food": "",
"Food_Alias": "",
"Unit_Alias": "",
"Keyword_Alias": "",
"Delete_Food": "",
"No_ID": "",
"Meal_Plan_Days": "",
"merge_title": "",
"move_title": "",
"Food": "",
"Original_Text": "",
"Recipe_Book": "",
"del_confirmation_tree": "",
"delete_title": "",
"create_title": "",
"edit_title": "",
"Name": "",
"Type": "",
"Description": "",
"Recipe": "",
"Date": "Datum",
"Share": "Sdílet",
"Automation": "Automatizace",
"Parameter": "Parametr",
"Export": "Export",
"Copy": "Kopírovat",
"Rating": "Hodnocení",
"Close": "Zavřít",
"Cancel": "Zrušit",
"Link": "Odkaz",
"Add": "Přidat",
"New": "Nový",
"Note": "Poznámka",
"Success": "Úspěch",
"Failure": "Selhání",
"Protected": "Chráněný",
"Ingredients": "Ingredience",
"Supermarket": "Obchod",
"Categories": "Kategorie",
"Category": "Kategorie",
"Selected": "Vybrané",
"min": "min",
"Servings": "Porce",
"Waiting": "Čekající",
"Preparation": "Příprava",
"External": "Externí",
"Size": "Velikost",
"Files": "Soubory",
"File": "Soubor",
"Edit": "Upravit",
"Image": "Obrázek",
"Delete": "Smazat",
"Open": "Otevřít",
"Ok": "Ok",
"Save": "Uložit",
"Step": "Krok",
"Search": "Hledat",
"Import": "Import",
"Print": "Tisk",
"Settings": "Nastavení",
"or": "nebo",
"and": "a",
"Information": "Informace",
"Download": "Stáhnout",
"Create": "Vytvořit",
"Search Settings": "Nastavení vyhledávání",
"View": "Zobrazit",
"Recipes": "Recepty",
"Move": "Přesunout",
"Merge": "Spojit",
"Parent": "Nadřazená",
"Copy Link": "Kopírovat odkaz",
"Copy Token": "Kopírovat token",
"delete_confirmation": "Jste si jistí, že chcete smazat {source}?",
"move_confirmation": "Přesunout <i>{child}</i> do nadřazené <i>{parent}</i>",
"merge_confirmation": "Nahradit <i>{source}</i> za <i>{target}</i>",
"create_rule": "a vytvořit automatizaci",
"move_selection": "Vybrat nadřazený {type} kam {source} přesunout.",
"merge_selection": "Nahradit všechny výskyty {source} za vybraný {type}.",
"Root": "Kořen",
"Ignore_Shopping": "Ignorovat nákupní seznam",
"Shopping_Category": "Kategorie nákupního seznamu",
"Shopping_Categories": "Kategorie nákupního seznamu",
"Edit_Food": "Upravit potravinu",
"Move_Food": "Přesunout potravinu",
"New_Food": "Nová potravina",
"Hide_Food": "Skrýt potravinu",
"Food_Alias": "Přezdívka potraviny",
"Unit_Alias": "Přezdívka jednotky",
"Keyword_Alias": "Přezdívka klíčového slova",
"Delete_Food": "Smazat potravinu",
"No_ID": "ID nenalezeno, odstranění není možné.",
"Meal_Plan_Days": "Budoucí jídelníčky",
"merge_title": "Sloučit {type}",
"move_title": "Přesunout {type}",
"Food": "Potravina",
"Original_Text": "Původní text",
"Recipe_Book": "Kuchařka",
"del_confirmation_tree": "Jste si jistí, že chcete odstranit {source} se všemi pořazenými ?",
"delete_title": "Smazat {type}",
"create_title": "Nový {type}",
"edit_title": "Upravit {type}",
"Name": "Jméno",
"Type": "Typ",
"Description": "Popis",
"Recipe": "Recept",
"tree_root": "",
"Icon": "",
"Unit": "",
"Decimals": "",
"Default_Unit": "",
"No_Results": "",
"New_Unit": "",
"Create_New_Shopping Category": "",
"Create_New_Food": "",
"Create_New_Keyword": "",
"Create_New_Unit": "",
"Create_New_Meal_Type": "",
"Create_New_Shopping_Category": "",
"and_up": "",
"and_down": "",
"Instructions": "",
"Unrated": "",
"Automate": "",
"Empty": "",
"Key_Ctrl": "",
"Key_Shift": "",
"Time": "",
"Text": "",
"Shopping_list": "",
"Added_by": "",
"Added_on": "",
"AddToShopping": "",
"IngredientInShopping": "",
"NotInShopping": "",
"OnHand": "",
"FoodOnHand": "",
"FoodNotOnHand": "",
"Undefined": "",
"Create_Meal_Plan_Entry": "",
"Edit_Meal_Plan_Entry": "",
"Title": "",
"Week": "",
"Month": "",
"Year": "",
"Planner": "",
"Planner_Settings": "",
"Period": "",
"Plan_Period_To_Show": "",
"Periods": "",
"Plan_Show_How_Many_Periods": "",
"Starting_Day": "",
"Meal_Types": "",
"Meal_Type": "",
"New_Entry": "",
"Clone": "",
"Drag_Here_To_Delete": "",
"Meal_Type_Required": "",
"Title_or_Recipe_Required": "",
"Color": "",
"New_Meal_Type": "",
"Use_Fractions": "",
"Use_Fractions_Help": "",
"AddFoodToShopping": "",
"RemoveFoodFromShopping": "",
"DeleteShoppingConfirm": "",
"IgnoredFood": "",
"Add_Servings_to_Shopping": "",
"Week_Numbers": "",
"Show_Week_Numbers": "",
"Export_As_ICal": "",
"Export_To_ICal": "",
"Cannot_Add_Notes_To_Shopping": "",
"Added_To_Shopping_List": "",
"Shopping_List_Empty": "",
"Next_Period": "",
"Previous_Period": "",
"Current_Period": "",
"Next_Day": "",
"Previous_Day": "",
"Inherit": "",
"InheritFields": "",
"FoodInherit": "",
"ShowUncategorizedFood": "",
"GroupBy": "",
"Language": "",
"Theme": "",
"SupermarketCategoriesOnly": "",
"MoveCategory": "",
"CountMore": "",
"IgnoreThis": "",
"DelayFor": "",
"Warning": "",
"NoCategory": "",
"InheritWarning": "",
"ShowDelayed": "",
"Completed": "",
"OfflineAlert": "",
"shopping_share": "",
"shopping_auto_sync": "",
"one_url_per_line": "",
"mealplan_autoadd_shopping": "",
"mealplan_autoexclude_onhand": "",
"mealplan_autoinclude_related": "",
"default_delay": "",
"plan_share_desc": "",
"shopping_share_desc": "",
"shopping_auto_sync_desc": "",
"mealplan_autoadd_shopping_desc": "",
"mealplan_autoexclude_onhand_desc": "",
"mealplan_autoinclude_related_desc": "",
"default_delay_desc": "",
"filter_to_supermarket": "",
"Coming_Soon": "",
"Auto_Planner": "",
"New_Cookbook": "",
"Hide_Keyword": "",
"Hour": "",
"Hours": "",
"Day": "",
"Days": "",
"Second": "",
"Seconds": "",
"Clear": "",
"Users": "",
"Invites": "",
"err_move_self": "",
"nothing": "",
"err_merge_self": "",
"show_sql": "",
"filter_to_supermarket_desc": "",
"CategoryName": "",
"SupermarketName": "",
"CategoryInstruction": "",
"shopping_recent_days_desc": "",
"shopping_recent_days": "",
"download_pdf": "",
"download_csv": "",
"csv_delim_help": "",
"csv_delim_label": "",
"SuccessClipboard": "",
"copy_to_clipboard": "",
"csv_prefix_help": "",
"csv_prefix_label": "",
"copy_markdown_table": "",
"in_shopping": "",
"DelayUntil": "",
"Pin": "",
"Unpin": "",
"PinnedConfirmation": "",
"UnpinnedConfirmation": "",
"mark_complete": "",
"QuickEntry": "",
"shopping_add_onhand_desc": "",
"shopping_add_onhand": "",
"related_recipes": "",
"today_recipes": "",
"sql_debug": "",
"remember_search": "",
"remember_hours": "",
"tree_select": "",
"OnHand_help": "",
"ignore_shopping_help": "",
"shopping_category_help": "",
"Icon": "Ikona",
"Unit": "Jednotka",
"Decimals": "Desetinná místa",
"Default_Unit": "Výchozí jednotka",
"No_Results": "Žádné výsledky",
"New_Unit": "Nová jednotka",
"Create_New_Shopping Category": "Vytvořit novou nákupní kategorii",
"Create_New_Food": "Přidat novou potravinu",
"Create_New_Keyword": "Přidat nové klíčové slovo",
"Create_New_Unit": "Přidat novou jednotku",
"Create_New_Meal_Type": "Přidat nový druh jídla",
"Create_New_Shopping_Category": "Přidat novou nákupní kategorii",
"and_up": "a nahoru",
"and_down": "a dolů",
"Instructions": "Instrukce",
"Unrated": "Nehodnocené",
"Automate": "Automatizovat",
"Empty": "Prázdné",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Time": "Čas",
"Text": "Text",
"Shopping_list": "Nákupní seznam",
"Added_by": "Přidáno uživatelem",
"Added_on": "Přidáno v",
"AddToShopping": "Přidat do nákupního seznamu",
"IngredientInShopping": "Tato ingredience je na vašem nákupním seznamu.",
"NotInShopping": "{food} není na vašem nákupním seznamu.",
"OnHand": "Momentálně k dispozici",
"FoodOnHand": "{food} máte k dispozici.",
"FoodNotOnHand": "Nemáte {food} k dispozici.",
"Undefined": "Neurčeno",
"Create_Meal_Plan_Entry": "Vytvořit položku v jídelníčku",
"Edit_Meal_Plan_Entry": "Upravit položku v jídelníčku",
"Title": "Název",
"Week": "Týden",
"Month": "Měsíc",
"Year": "Rok",
"Planner": "Plánovač",
"Planner_Settings": "Nastavení plánovače",
"Period": "Období",
"Plan_Period_To_Show": "Zobrazit týdny, měsíce nebo roky",
"Periods": "Období",
"Plan_Show_How_Many_Periods": "Kolik období bude zobrazeno",
"Starting_Day": "První den v týdnu",
"Meal_Types": "Druhy jídel",
"Meal_Type": "Druh jídla",
"New_Entry": "Nová položka",
"Clone": "Klonovat",
"Drag_Here_To_Delete": "Přesunutím sem smazat",
"Meal_Type_Required": "Druh jídla je povinný",
"Title_or_Recipe_Required": "Je požadován název nebo výběr receptu",
"Color": "Barva",
"New_Meal_Type": "Nový druh jídla",
"Use_Fractions": "Použít zlomky",
"Use_Fractions_Help": "Automaticky převézt desetinná čísla na zlomky při prohlížení repetu.",
"AddFoodToShopping": "Přidat {food} na váš nákupní seznam",
"RemoveFoodFromShopping": "Odstranit {food} z nákupního seznamu",
"DeleteShoppingConfirm": "Jste si jistí, že chcete odstranit všechno {food} z nákupního seznamu?",
"IgnoredFood": "{food} bude ignorovat nákup.",
"Add_Servings_to_Shopping": "Přidat {servings} porce na nákupní seznam",
"Week_Numbers": "Číslo týdne",
"Show_Week_Numbers": "Zobrazit čísla týdnů?",
"Export_As_ICal": "Exportovat současný úsek do formátu iCal",
"Export_To_ICal": "Export ovat .ics",
"Cannot_Add_Notes_To_Shopping": "Poznámky nemohou být přidány na nákupní seznam",
"Added_To_Shopping_List": "Přidáno na nákupní seznam",
"Shopping_List_Empty": "Váš nákupní seznam je momentálně prázdný, můžete přidat položky pomocí kontextového menu záznamu v jídelníčku (pravým kliknutím na kartu nebo levým kliknutím na ikonu menu)",
"Next_Period": "Další období",
"Previous_Period": "Předchozí období",
"Current_Period": "Současné období",
"Next_Day": "Následující den",
"Previous_Day": "Předchozí den",
"Inherit": "Propsat",
"InheritFields": "Propsat hodnoty polí",
"FoodInherit": "Propisovatelná pole potraviny",
"ShowUncategorizedFood": "Zobrazit nedefinované",
"GroupBy": "Seskupit podle",
"Language": "Jazyk",
"Theme": "Téma",
"SupermarketCategoriesOnly": "Pouze kategorie obchodu",
"MoveCategory": "Přesunout do: ",
"CountMore": "...+{count} víc",
"IgnoreThis": "Nikdy automaticky nepřídávat {food} na nákupní seznam",
"DelayFor": "Odložit na {hours} hodin",
"Warning": "Varování",
"NoCategory": "Není vybrána žádná kategorie.",
"InheritWarning": "{food} se propisuje, změny nemusí setrvat.",
"ShowDelayed": "Zobrazit odložené položky",
"Completed": "Dokončeno",
"OfflineAlert": "Jste offline, nákupní seznam nemusí být synchronizován.",
"shopping_share": "Sdílet nákupní seznam",
"shopping_auto_sync": "Automatická synchronizace",
"one_url_per_line": "Jeden URL odkaz na řádek",
"mealplan_autoadd_shopping": "Automaticky přidat jídelníček",
"mealplan_autoexclude_onhand": "Nezahrnovat potraviny k dispozici",
"mealplan_autoinclude_related": "Přidat podobné recepty",
"default_delay": "Výchozí doba odložení v hodinách",
"plan_share_desc": "Nové položky v jídelníčku budou automaticky sdíleny s vybranými uživateli.",
"shopping_share_desc": "Uživatelé uvidí všechny položky na vašem nákupním seznamu. Abyste viděli položky na jejich seznamu, musí si přidat vás.",
"shopping_auto_sync_desc": "Nastavením 0 dojde k vypnutí automatické synchronizace. Při prohlížení nákupního seznamu je vždy po uplynutí nastaveného počtu vteřin aktualizován o změny, které mohli provést jiní uživatelé. To je užitečné, pokud nakupujete ve více lidech, ale může používat více dat.",
"mealplan_autoadd_shopping_desc": "Automaticky podle jídelníčku přidat ingredience na nákupní seznam.",
"mealplan_autoexclude_onhand_desc": "Nepřidávat ingredience, které jsou k dispozici, na nákupní seznam, když je vytvořen podle jídelníčku (manuálně nebo automaticky).",
"mealplan_autoinclude_related_desc": "Když je nákupní seznam vytvořen podle jídelníčku, přidat i položky z přidružených receptů.",
"default_delay_desc": "Výchozí odložení položek v nákupním seznamu v hodinách.",
"filter_to_supermarket": "Filtrovat podle obchodu",
"Coming_Soon": "Již brzy",
"Auto_Planner": "Automatický plánovač",
"New_Cookbook": "Nová kuchařka",
"Hide_Keyword": "Skrýt klíčová slova",
"Hour": "Hodina",
"Hours": "Hodiny",
"Day": "Den",
"Days": "Dny",
"Second": "Vteřina",
"Seconds": "Vteřiny",
"Clear": "Vyčistit",
"Users": "Uživatelé",
"Invites": "Pozvánky",
"err_move_self": "Není možné přesunout jednu položku do sebe samé",
"nothing": "Není co dělat",
"err_merge_self": "Není možné sloučit položku samu se sebou",
"show_sql": "Zobrazit SQL",
"filter_to_supermarket_desc": "Standartně zobrazovat položky v nákupním seznamu pouze pro vybraný obchod.",
"CategoryName": "Název kategorie",
"SupermarketName": "Název obchodu",
"CategoryInstruction": "Přetáhnutím kategorií změníte pořadí, ve kterém se zobrazují v nákupním seznamu.",
"shopping_recent_days_desc": "Počet dní k zobrazení posledních přidaných položek na nákupním seznamu.",
"shopping_recent_days": "Nedávné dny",
"download_pdf": "Stáhnout PDF",
"download_csv": "Stáhnout CSV",
"csv_delim_help": "Který znak bude použit pro oddělení záznamů v CSV.",
"csv_delim_label": "Oddělovač záznamů v CSV",
"SuccessClipboard": "Nákupní seznam byl zkopírován do schránky",
"copy_to_clipboard": "Zkopírovat do schránky",
"csv_prefix_help": "Prefix přidaný ke zkopírovanému seznamu do schránky.",
"csv_prefix_label": "Prefix seznamu",
"copy_markdown_table": "Kopírovat jako Markdown tabulku",
"in_shopping": "V nákupním seznamu",
"DelayUntil": "Odložit do",
"Pin": "Připnout",
"Unpin": "Odepnout",
"PinnedConfirmation": "{recipe} byl připnut.",
"UnpinnedConfirmation": "{recipe} byl odepnut.",
"mark_complete": "Označit jako hotové",
"QuickEntry": "Rychlý záznam",
"shopping_add_onhand_desc": "Označit potravinu jako \"K dispozici\" když je odškrtnuta na nákupním seznamu.",
"shopping_add_onhand": "Automaticky K dispozici",
"related_recipes": "Související recepty",
"today_recipes": "Dnešní recepty",
"sql_debug": "SQL Debug",
"remember_search": "Pamatovat vyhledávání",
"remember_hours": "Kolik hodin pamatovat",
"tree_select": "Použít stromový výběr",
"OnHand_help": "Potravina je v inventáři a nebude automaticky přidána na nákupní seznam. Status \"k dipozici\" je sdílen s nakupujícími uživateli.",
"ignore_shopping_help": "Nikdy nepřidávat potravinu na nákupní seznam (např. voda)",
"shopping_category_help": "Obchody mohou být seřazeny a třízeny pomocí nákupních kategorií podle rozvržení uliček a regálů.",
"food_recipe_help": "",
"Foods": "",
"Account": "",
"Cosmetic": "",
"API": "",
"enable_expert": "",
"expert_mode": "",
"simple_mode": "",
"advanced": "",
"fields": "",
"show_keywords": "",
"show_foods": "",
"show_books": "",
"show_rating": "",
"show_units": "",
"show_filters": "",
"not": "",
"save_filter": "",
"filter_name": "",
"left_handed": "",
"left_handed_help": "",
"Custom Filter": "",
"shared_with": "",
"sort_by": "",
"asc": "",
"desc": "",
"date_viewed": "",
"last_cooked": "",
"times_cooked": "",
"date_created": "",
"show_sortby": "",
"Foods": "Potraviny",
"Account": "Účet",
"Cosmetic": "Zobrazení",
"API": "API",
"enable_expert": "Povolit Expertní režim",
"expert_mode": "Expertní režim",
"simple_mode": "Jednoduchý režim",
"advanced": "Pokročilé",
"fields": "Pole",
"show_keywords": "Zobrazit klíčová slova",
"show_foods": "Zobrazit potraviny",
"show_books": "Zobrazit kuchařky",
"show_rating": "Zobrazit hodnocení",
"show_units": "Zobrazit jednotky",
"show_filters": "Zobrazit filtry",
"not": "ne",
"save_filter": "Uložit filtr",
"filter_name": "Název filtru",
"left_handed": "Režim pro leváky",
"left_handed_help": "Optimalizuje uživatelské prostředí pro levou ruku.",
"Custom Filter": "Uživatelský filtr",
"shared_with": "Sdíleno s",
"sort_by": "Seřadit podle",
"asc": "Vzestupně",
"desc": "Sestupně",
"date_viewed": "Poslední prohlížené",
"last_cooked": "Naposledy vařeno",
"times_cooked": "Kolkrát vařeno",
"date_created": "Datum vytvoření",
"show_sortby": "Zobrazit Seřazeno podle",
"search_rank": "",
"make_now": "",
"recipe_filter": "",
"book_filter_help": "",
"review_shopping": "",
"view_recipe": "",
"copy_to_new": "",
"recipe_name": "",
"paste_ingredients_placeholder": "",
"paste_ingredients": "",
"ingredient_list": "",
"explain": "",
"filter": "",
"Website": "",
"App": "",
"Message": "",
"Bookmarklet": "",
"Sticky_Nav": "",
"Sticky_Nav_Help": "",
"Nav_Color": "",
"Nav_Color_Help": "",
"Use_Kj": "",
"Comments_setting": "",
"click_image_import": "",
"no_more_images_found": "",
"import_duplicates": "",
"paste_json": "",
"Click_To_Edit": "",
"search_no_recipes": "",
"search_import_help_text": "",
"search_create_help_text": "",
"warning_duplicate_filter": "",
"reset_children": "",
"recipe_filter": "Filtrovat recepty",
"book_filter_help": "Zahrnout i recepty z filtru stejně jako manuálně přidané.",
"review_shopping": "Zkontrolovat nákupní položky před uložením",
"view_recipe": "Zobrazit recept",
"copy_to_new": "Zkopírovat do nového receptu",
"recipe_name": "Název receptu",
"paste_ingredients_placeholder": "Zde vložit seznam ingrediencí.",
"paste_ingredients": "Vložit ingredince",
"ingredient_list": "Seznam ingrediencí",
"explain": "Vysvětlit",
"filter": "Filtr",
"Website": "Web",
"App": "Aplikace",
"Message": "Zpráva",
"Bookmarklet": "Skript v záložce",
"Sticky_Nav": "Připnout navigační panel",
"Sticky_Nav_Help": "Vždy zobrazit navigační panel na vrchu stránky.",
"Nav_Color": "Barva navigačního panelu",
"Nav_Color_Help": "Zmenit barvu navigačního panelu.",
"Use_Kj": "Používat kJ místo kcal",
"Comments_setting": "Zobrazit komentáře",
"click_image_import": "Vyberte obrázek, který chcete přiřadit k tomuto receptu",
"no_more_images_found": "Žádné další obrázky na zadaném odkazu.",
"import_duplicates": "Aby bylo zamezeno duplicitním receptům, recepty se stejným jménem jako již existující jsou ignorovány. Pokud chcete přidat všechno, zaškrtněte toto políčko.",
"paste_json": "Sem zkopírujte zdroj ve formátu json nebo html.",
"Click_To_Edit": "Kliknutím editovat",
"search_no_recipes": "Nebyly nealezeny žádné recepty!",
"search_import_help_text": "Importovat recept z externí webové stránky nebo aplikace.",
"search_create_help_text": "Vytvořit nový recept přímo v Tandoor.",
"warning_duplicate_filter": "Varování: Kvůli technickým omezení může použití několika filtrů se stejnou kombinací (a/nebo/ne) přinést neočekávaný výsledek.",
"reset_children": "Resetovat propsání podřízených",
"reset_children_help": "",
"reset_food_inheritance": "",
"reset_food_inheritance": "Resetovat propisování",
"reset_food_inheritance_info": "",
"substitute_help": "",
"substitute_siblings_help": "",
"substitute_children_help": "",
"substitute_siblings": "",
"substitute_children": "",
"SubstituteOnHand": "",
"ChildInheritFields": "",
"ChildInheritFields_help": "",
"InheritFields_help": "",
"show_ingredient_overview": "",
"Ingredient Overview": "",
"last_viewed": "",
"created_on": "",
"updatedon": "",
"Imported_From": "",
"advanced_search_settings": "",
"nothing_planned_today": "",
"no_pinned_recipes": "",
"Planned": "",
"Pinned": "",
"Imported": "",
"Quick actions": "",
"Ratings": "",
"Internal": "",
"Units": "",
"Manage_Emails": "",
"Change_Password": "",
"Social_Authentication": "",
"Random Recipes": "",
"parameter_count": "",
"select_keyword": "",
"add_keyword": "",
"select_file": "",
"select_recipe": "",
"select_unit": "",
"select_food": "",
"remove_selection": "",
"empty_list": "",
"Select": "",
"Supermarkets": "",
"User": "",
"Username": "",
"First_name": "",
"Last_name": "",
"Keyword": "",
"Advanced": "",
"Page": "",
"Single": "",
"Multiple": "",
"Reset": "",
"Disabled": "",
"Disable": "",
"Options": "",
"Create Food": "",
"create_food_desc": "",
"additional_options": "",
"Importer_Help": "",
"Documentation": "",
"Select_App_To_Import": "",
"Import_Supported": "",
"Export_Supported": "",
"Import_Not_Yet_Supported": "",
"Export_Not_Yet_Supported": "",
"Import_Result_Info": "",
"Recipes_In_Import": "",
"Toggle": "",
"Import_Error": "",
"Warning_Delete_Supermarket_Category": "",
"New_Supermarket": "",
"New_Supermarket_Category": "",
"Are_You_Sure": "",
"Valid Until": "",
"Split_All_Steps": "",
"Combine_All_Steps": "",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": "",
"Create Recipe": "",
"Import Recipe": ""
"substitute_help": "Při hledání podle ingrediencí, které jsou k dispozici, jsou zvažovány náhrady.",
"substitute_siblings_help": "Všechny potraviny, které sdílejí nadřazenou položku jsou považovány za náhrady.",
"substitute_children_help": "Všechny potraviny, které jsou podřízeny této, jsou považovány za náhražky.",
"substitute_siblings": "Související náhrady",
"substitute_children": "Podřízené náhrady",
"SubstituteOnHand": "Máte k dispozici náhradu.",
"ChildInheritFields": "Propisovaná pole podřízených",
"ChildInheritFields_help": "Podřízeným se budou standardně propisovat tato pole.",
"InheritFields_help": "Hodnoty těchto polí budou propsány z nadřazených (Výjimka: prázdné nákupní kategorie nejsou propsány)",
"show_ingredient_overview": "Zobrazit seznam všech ingrediencí na začátku receptu.",
"Ingredient Overview": "Přehled ingrediencí",
"last_viewed": "Naposledy zobrazeno",
"created_on": "Vytvořeno",
"updatedon": "Upraveno",
"Imported_From": "Importováno z",
"advanced_search_settings": "Rozšířené vyhledávání",
"nothing_planned_today": "Dnes nemáte nic naplánováno!",
"no_pinned_recipes": "Nemáte žádné připnuté recepty!",
"Planned": "Naplánované",
"Pinned": "Připnuté",
"Imported": "Importované",
"Quick actions": "Rychlé akce",
"Ratings": "Hodnocení",
"Internal": "Interní",
"Units": "Jednotky",
"Manage_Emails": "Spravovat emaily",
"Change_Password": "Změna hesla",
"Social_Authentication": "Přihlašování pomocí účtů sociálních sítí",
"Random Recipes": "Náhodné recepty",
"parameter_count": "Parametr {count}",
"select_keyword": "Vybrat klíčové slovo",
"add_keyword": "Přidat klíčové slovo",
"select_file": "Vybrat soubor",
"select_recipe": "Vybrat recept",
"select_unit": "Vybrat jednotku",
"select_food": "Vybrat potravinu",
"remove_selection": "Odznačit",
"empty_list": "Seznam je prázdný.",
"Select": "Vybrat",
"Supermarkets": "Obchody",
"User": "Uživatel",
"Username": "Uživatelské jméno",
"First_name": "Jméno",
"Last_name": "Příjmení",
"Keyword": "Klíčové slovo",
"Advanced": "Rozšířené",
"Page": "Stránka",
"Single": "Jednoduchý",
"Multiple": "Vícenásobný",
"Reset": "Resetovat",
"Disabled": "Deaktivované",
"Disable": "Deaktivovat",
"Options": "Možnosti",
"Create Food": "Vytvořit potravinu",
"create_food_desc": "Vytvořit potravinu a propojit ji s tímto receptem.",
"additional_options": "Rozšířené možnosti",
"Importer_Help": "Nápověda k importu z této aplikace:",
"Documentation": "Dokumentace",
"Select_App_To_Import": "Vyberte aplikaci, ze které chcete importovat",
"Import_Supported": "Import podporován",
"Export_Supported": "Export podporován",
"Import_Not_Yet_Supported": "Import není zatím podporován",
"Export_Not_Yet_Supported": "Export není zatím podporován",
"Import_Result_Info": "{imported} z {total} receptů naimportováno",
"Recipes_In_Import": "Receptů v importním souboru",
"Toggle": "Přepnout",
"Import_Error": "Během importu došlo k chybě. Pro více informací rozbalte Detaily na konci stránky.",
"Warning_Delete_Supermarket_Category": "Vymazáním kategorie obchodu dojde k odstranění všech vazeb na potraviny. Jste si jistí?",
"New_Supermarket": "Vytvořit nový obchod",
"New_Supermarket_Category": "Vytvořit novou kategorii obchodu",
"Are_You_Sure": "Jste si jistí?",
"Valid Until": "Platné do",
"Split_All_Steps": "Rozdělit každý řádek do samostatného kroku.",
"Combine_All_Steps": "Zkombinovat všechny kroky do jednoho kroku.",
"Plural": "Množné číslo",
"plural_short": "množné číslo",
"Use_Plural_Unit_Always": "Vždy použít množné číslo pro jednotku",
"Use_Plural_Unit_Simple": "Dynamicky použít množné číslo pro jednotku",
"Use_Plural_Food_Always": "Použít u potraviny vždy množné číslo",
"Use_Plural_Food_Simple": "Použít u potraviny množné číslo dynamicky",
"plural_usage_info": "Použít množné číslo pro jednotky a potraviny v tomto prostoru.",
"Create Recipe": "Vytvořit recept",
"Import Recipe": "Importovat recept",
"per_serving": "na porci",
"open_data_help_text": "Projekt Tandoor Open Data nabízí komunitou poskytnutá data pro Tandoor. Toto pole je automaticky vyplněno při importu a může být později upraveno.",
"Data_Import_Info": "Rozšiřte svůj prostor o seznamy potravin, jednotek a další spravované komunitou, a vylepšete tak svoji sbírku receptů.",
"Update_Existing_Data": "Aktualizovat existující data",
"Use_Metric": "Používat metrické jednotky",
"Learn_More": "Zjistit víc",
"converted_unit": "Převedená jendotka",
"converted_amount": "Převedené množství",
"base_unit": "Základní jednotka",
"base_amount": "Základní množství",
"Datatype": "Datový typ",
"Number of Objects": "Počet Objektů",
"Property": "Vlastnost",
"Conversion": "Převod",
"Properties": "Vlastnosti",
"recipe_property_info": "Můžete také přidávat vlastnosti k Vašim potravinám. Hodnoty budou automaticky přepočteny na základě Vašeho receptu!",
"total": "celkem"
}

View File

@ -446,7 +446,6 @@
"Valid Until": "Gyldig indtil",
"Private_Recipe_Help": "Opskriften er kun synlig for dig, og dem som den er delt med.",
"food_inherit_info": "Felter på mad som skal nedarves automatisk.",
"facet_count_info": "Vis opskriftsantal på søgeresultater.",
"Copy Link": "Kopier link",
"Copy Token": "Kopier token",
"show_ingredient_overview": "Vis en liste af alle ingredienser i starten af en opskrift.",

View File

@ -72,7 +72,7 @@
"Cancel": "Abbrechen",
"success_deleting_resource": "Ressource erfolgreich gelöscht!",
"Load_More": "Weitere laden",
"Ok": "Öffnen",
"Ok": "Ok",
"Link": "Link",
"Key_Ctrl": "Strg",
"move_title": "{type} verschieben",
@ -114,7 +114,7 @@
"Create_New_Shopping Category": "Neue Einkaufskategorie erstellen",
"Automate": "Automatisieren",
"Type": "Typ",
"and_up": "& Höher",
"and_up": "& Hoch",
"Unrated": "Unbewertet",
"Shopping_list": "Einkaufsliste",
"step_time_minutes": "Schritt Dauer in Minuten",
@ -140,6 +140,7 @@
"advanced_search_settings": "Erweiterte Sucheinstellungen",
"View": "Ansicht",
"Recipes": "Rezepte",
"Welcome": "Willkommen",
"Move": "Verschieben",
"Merge": "Zusammenführen",
"Parent": "Eltern",
@ -206,7 +207,7 @@
"New_Cookbook": "Neues Kochbuch",
"Coming_Soon": "Bald verfügbar",
"Auto_Planner": "Smart Planen",
"Hide_Keyword": "Keywords schließen",
"Hide_Keyword": "Schlüsselwörter verbergen",
"Clear": "Leeren",
"GroupBy": "Gruppieren nach",
"IgnoreThis": "Füge {food} nie automatisch zur Einkaufsliste hinzu",
@ -222,11 +223,11 @@
"NoCategory": "Keine Kategorie ausgewählt.",
"ShowDelayed": "Zeige verschobene Elemente",
"Completed": "Fertig",
"OfflineAlert": "Du bist offline, deine Einkaufsliste wird nicht synchronisiert.",
"OfflineAlert": "Du bist offline. Deine Einkaufsliste wird nicht synchronisiert.",
"shopping_share": "Einkaufsliste teilen",
"mealplan_autoadd_shopping": "Automatisches Hinzufügen zum Essensplan",
"mealplan_autoexclude_onhand": "Ignoriere vorrätige Zutaten",
"mealplan_autoinclude_related": "Füge verwandte Rezepte hinzu",
"mealplan_autoinclude_related": "Ähnliche Rezepte hinzufügen",
"default_delay": "Standard-Verzögerungszeit",
"Added_by": "Hinzugefügt durch",
"AddToShopping": "Zur Einkaufsliste hinzufügen",
@ -241,7 +242,7 @@
"IngredientInShopping": "Diese Zutat befindet sich auf Ihrer Einkaufsliste.",
"NotInShopping": "{food} befindet sich nicht auf Ihrer Einkaufsliste.",
"OnHand": "Aktuell vorrätig",
"FoodNotOnHand": "Sie habe {food} nicht vorrätig.",
"FoodNotOnHand": "Sie haben {food} nicht vorrätig.",
"Undefined": "undefiniert",
"AddFoodToShopping": "Fügen Sie {food} zur Einkaufsliste hinzu",
"RemoveFoodFromShopping": "{food} von der Einkaufsliste löschen",
@ -251,23 +252,23 @@
"mealplan_autoadd_shopping_desc": "Zutaten aus dem Essensplan automatisch zur Einkaufsliste hinzufügen.",
"Pin": "Anheften",
"mark_complete": "Vollständig markieren",
"shopping_add_onhand_desc": "Markiere Lebensmittel als \"Vorrätig\", wenn von der Einkaufsliste abgehakt wurden.",
"shopping_add_onhand_desc": "Zutat beim Abhaken auf der Einkausfliste als \"vorrätig\" kennzeichnen.",
"left_handed": "Linkshänder-Modus",
"left_handed_help": "Optimiert die Benutzeroberfläche für die Bedienung mit der linken Hand.",
"FoodInherit": "Lebensmittel vererbbare Felder",
"SupermarketCategoriesOnly": "Nur Supermarktkategorien",
"InheritWarning": "{food} ist auf Vererbung gesetzt ist, Änderungen werden möglicherweise nicht gespeichert.",
"mealplan_autoexclude_onhand_desc": "Beim (manuellen oder automatischen) Hinzufügen eines Essensplans zur Einkaufsliste vorrätige Zutagen ausnehmen.",
"InheritWarning": "{food} ist auf Vererbung gesetzt, Änderungen werden möglicherweise nicht gespeichert.",
"mealplan_autoexclude_onhand_desc": "Wenn ein Speiseplan zur Einkaufsliste zugefügt wird (manuell oder automatisch), Zutaten ausschliessen, die gerade vorrätig sind.",
"mealplan_autoinclude_related_desc": "Wenn Sie einen Essensplan zur Einkaufsliste hinzufügen (manuell oder automatisch), fügen Sie alle zugehörigen Rezepte hinzu.",
"default_delay_desc": "Voreingestellte Anzahl von Stunden für die Verzögerung eines Einkaufslisteneintrags.",
"filter_to_supermarket": "Nach Supermarkt filtern",
"err_move_self": "Element kann nicht auf sich selbst verschoben werden",
"nothing": "Nichts zu tun",
"err_merge_self": "Element kann nicht mit sich selbst zusammengeführt werden",
"show_sql": "SQL anzeigen",
"show_sql": "Zeige SQL",
"filter_to_supermarket_desc": "Standardmäßig wird die Einkaufsliste so gefiltert, dass sie nur Kategorien für den ausgewählten Supermarkt enthält.",
"CategoryName": "Kategorie Name",
"SupermarketName": "Supermarkt Name",
"CategoryName": "Kategorienname",
"SupermarketName": "Name Supermarkt",
"CategoryInstruction": "Ziehen Sie Kategorien, um die Reihenfolge zu ändern, in der die Kategorien in der Einkaufsliste erscheinen.",
"shopping_recent_days_desc": "Tage der letzten Einträge in der Einkaufsliste, die angezeigt werden sollen.",
"shopping_recent_days": "Letzte Tage",
@ -277,7 +278,7 @@
"csv_delim_help": "Trennzeichen für CSV-Exporte.",
"csv_delim_label": "CSV-Trennzeichen",
"SuccessClipboard": "Einkaufsliste wurde in die Zwischenablage kopiert",
"copy_to_clipboard": "In die Zwischenablage kopieren",
"copy_to_clipboard": "In Zwischenablage kopieren",
"csv_prefix_help": "Präfix, das beim Kopieren der Liste in die Zwischenablage hinzugefügt wird.",
"csv_prefix_label": "Listenpräfix",
"copy_markdown_table": "Als Markdown-Tabelle kopieren",
@ -291,12 +292,12 @@
"remember_search": "Suchbegriff merken",
"remember_hours": "Stunden zu erinnern",
"tree_select": "Baum-Auswahl verwenden",
"CountMore": "...+{count} weitere",
"ignore_shopping_help": "Füge Zutat nie zur Einkaufsliste hinzu (z.B. Wasser)",
"CountMore": "...+{count} mehr",
"ignore_shopping_help": "Zutat nie auf Einkaufsliste setzen (z.B. Wasser)",
"OnHand_help": "Lebensmittel ist \"Vorrätig\" und wird nicht automatisch zur Einkaufsliste hinzugefügt. Der Status \"Vorrätig\" wird mit den Benutzern der Einkaufsliste geteilt.",
"shopping_category_help": "Supermärkte können nach Einkaufskategorien geordnet und gefiltert werden, je nachdem, wie die Gänge angeordnet sind.",
"shopping_category_help": "Einkaufsläden können nach Produktkategorie entsprechend der Anordnung der Regalreihen sortiert werden.",
"Foods": "Lebensmittel",
"food_recipe_help": "Wird ein Rezept hier verknüpft, wird diese Verknüpfung in allen anderen Rezepten übernommen, die dieses Lebensmittel beinhaltet",
"food_recipe_help": "Wird ein Rezept hier verknüpft, wird diese Verknüpfung in allen anderen Rezepten übernommen, die dieses Lebensmittel beinhalten",
"review_shopping": "Überprüfe die Einkaufsliste vor dem Speichern",
"view_recipe": "Rezept anschauen",
"Planned": "Geplant",
@ -359,10 +360,10 @@
"Protected": "Geschützt",
"not": "nicht",
"warning_duplicate_filter": "Warnung: Wegen technischen Limitierungen können mehrere Filter der selben Kombination (und/oder/nicht) zu unerwarteten Ergebnissen führen.",
"and_down": "& Niedriger",
"and_down": "& Runter",
"enable_expert": "Expertenmodus aktivieren",
"filter_name": "Name des Filters",
"shared_with": "Geteilt mit",
"filter_name": "Filtername",
"shared_with": "geteilt mit",
"asc": "Aufsteigend",
"desc": "Absteigend",
"book_filter_help": "Schließt zusätzlich zu den manuell hinzugefügten Rezepten, alle Rezepte die dem Filter entsprechen ein.",
@ -407,11 +408,10 @@
"Warning_Delete_Supermarket_Category": "Die Löschung einer Supermarktkategorie werden auch alle Beziehungen zu Lebensmitteln gelöscht. Bist du dir sicher?",
"New_Supermarket": "Erstelle einen neuen Supermarkt",
"New_Supermarket_Category": "Erstelle eine neue Supermarktkategorie",
"warning_space_delete": "Du kannst deinen Bereich inklusive all deiner Rezepte, Einkaufslisten, Essensplänen und allem anderen, die du erstellt hast löschen. Dieser Schritt kann nicht rückgängig gemacht werden! Bist du sicher, dass du das tun möchtest?",
"Copy Link": "Link kopieren",
"warning_space_delete": "Du kannst deinen Space inklusive all deiner Rezepte, Shoppinglisten, Essensplänen und allem anderen, das du erstellt hast löschen. Dieser Schritt kann nicht rückgängig gemacht werden! Bist du sicher, dass du das tun möchtest?",
"Copy Link": "Link Kopieren",
"Users": "Benutzer",
"facet_count_info": "Zeige die Anzahl der Rezepte auf den Suchfiltern.",
"Copy Token": "Token kopieren",
"Copy Token": "Kopiere Token",
"Invites": "Einladungen",
"Message": "Nachricht",
"Bookmarklet": "Lesezeichen",
@ -460,9 +460,9 @@
"Comments_setting": "Kommentare anzeigen",
"reset_food_inheritance": "Vererbung zurücksetzen",
"food_inherit_info": "Datenfelder des Lebensmittels, die standardmäßig vererbt werden sollen.",
"Are_You_Sure": "Bist du dir sicher?",
"Are_You_Sure": "Sind Sie sicher?",
"Plural": "Plural",
"plural_short": "pl.",
"plural_short": "Plural",
"Use_Plural_Unit_Always": "Pluralform der Maßeinheit immer verwenden",
"Use_Plural_Unit_Simple": "Pluralform der Maßeinheit dynamisch anpassen",
"Use_Plural_Food_Always": "Pluralform des Essens immer verwenden",
@ -473,11 +473,42 @@
"UnpinnedConfirmation": "{recipe} wurde gelöst.",
"Description_Replace": "Beschreibung ersetzen",
"Instruction_Replace": "Anleitung ersetzen",
"Split_All_Steps": "Teile alle Zeilen in seperate Schritte auf.",
"Split_All_Steps": "Teile alle Zeilen in separate Schritte auf.",
"Auto_Sort_Help": "Verschiebe alle Zutaten zu dem Schritt, der am Besten passt.",
"Combine_All_Steps": "Fasse alle Schritte in einem einzelnem Feld zusammen.",
"reset_children_help": "Überschreibe alle Kinder mit den Werten der vererbten Felder. Die vererbten Felder der Kinder werden als vererbte Felder gesetzt, es sei denn, das Kind-Vererben-Feld ist gesetzt.",
"Unpin": "Lösen",
"Amount": "Menge",
"Original_Text": "Originaltext"
"Back": "Zurück",
"Original_Text": "Originaler Text",
"Choose_Category": "Kategorie Auswählen",
"Import Recipe": "Rezept importieren",
"Create Recipe": "Rezept erstellen",
"recipe_property_info": "Sie können auch Eigenschaften zu Lebensmitteln hinzufügen, um sie automatisch auf der Grundlage Ihres Rezepts zu berechnen!",
"per_serving": "pro Portion",
"open_data_help_text": "Das Tandoor Open Data Projekt bietet von der Gemeinschaft bereitgestellte Daten für Tandoor. Dieses Feld wird beim Importieren automatisch ausgefüllt und ermöglicht künftige Aktualisierungen.",
"Open_Data_Import": "Datenimport öffnen",
"Update_Existing_Data": "Vorhandene Daten aktualisieren",
"Data_Import_Info": "Verbessern Sie Ihren Space, indem Sie eine von der Community kuratierte Liste von Lebensmitteln, Einheiten und mehr importieren, um Ihre Rezeptsammlung zu verbessern.",
"Learn_More": "Mehr erfahren",
"Use_Metric": "Metrische Einheiten verwenden",
"converted_unit": "Umgerechnete Einheit",
"converted_amount": "Umgerechneter Betrag",
"base_unit": "Basiseinheit",
"base_amount": "Grundbetrag",
"Datatype": "Datentyp",
"Number of Objects": "Anzahl von Objekten",
"Property": "Eigenschaft",
"Conversion": "Umrechnung",
"Properties": "Eigenschaften",
"total": "gesamt",
"Open_Data_Slug": "Open Data Slug",
"g": "Gramm [g] (metrisch, Gewicht)",
"kg": "Kilogramm [kg] (metrisch, Gewicht)",
"ounce": "Unze [oz] (Gewicht)",
"pound": "Pfund (Gewicht)",
"ml": "Milliliter",
"l": "Liter",
"tbsp": "Esslöffel",
"tsp": "Teelöffel"
}

521
vue/src/locales/el.json Normal file
View File

@ -0,0 +1,521 @@
{
"warning_feature_beta": "Αυτή η λειτουργία βρίσκεται αυτήν τη στιγμή σε κατάσταση BETA (δοκιμαστική). Παρακαλούμε να αναμένετε σφάλματα και πιθανές αλλαγές που μπορεί να προκαλέσουν απώλεια δεδομένων που σχετίζονται με τις διάφορες λειτουργίες στο μέλλον.",
"err_fetching_resource": "Παρουσιάστηκε ένα σφάλμα κατά τη λήψη ενός πόρου!",
"err_creating_resource": "Παρουσιάστηκε ένα σφάλμα κατά τη δημιουργία ενός πόρου!",
"err_updating_resource": "Παρουσιάστηκε ένα σφάλμα κατά την ενημέρωση ενός πόρου!",
"err_deleting_resource": "Παρουσιάστηκε ένα σφάλμα κατά τη διαγραφή ενός πόρου!",
"err_deleting_protected_resource": "Το αντικείμενο που προσπαθείτε να διαγράψετε είναι σε χρήση και δεν μπορεί να διαγραφεί.",
"err_moving_resource": "Παρουσιάστηκε ένα σφάλμα κατά τη μετακίνηση ενός πόρου!",
"err_merging_resource": "Παρουσιάστηκε ένα σφάλμα κατά τη συγχώνευση ενός πόρου!",
"success_fetching_resource": "Επιτυχής λήψη πόρου!",
"success_creating_resource": "Επιτυχής δημιουργία πόρου!",
"success_updating_resource": "Επιτυχής ενημέρωση πόρου!",
"success_deleting_resource": "Επιτυχής διαγραφή πόρου!",
"success_moving_resource": "Επιτυχής μετακίνηση πόρου!",
"success_merging_resource": "Επιτυχής συγχώνευση πόρου!",
"file_upload_disabled": "Το ανέβασμα αρχείων δεν είναι ενεργοποιημένο για τον χώρο σας.",
"recipe_property_info": "Μπορείτε επίσης να προσθέσετε ιδιότητες σε φαγητά ώστε να υπολογίζονται αυτόματα βάσει της συνταγής σας!",
"warning_space_delete": "Μπορείτε να διαγράψετε τον χώρο σας μαζί με όλες τις συνταγές, τις λίστες αγορών, τα προγράμματα γευμάτων και οτιδήποτε άλλο έχετε δημιουργήσει. Η ενέργεια αυτή είναι μη αναστρέψιμη! Θέλετε σίγουρα να το κάνετε;",
"food_inherit_info": "Πεδία σε φαγητά τα οποία πρέπει να κληρονομούνται αυτόματα.",
"step_time_minutes": "Χρόνος βήματος σε λεπτά",
"confirm_delete": "Θέλετε σίγουρα να διαγράψετε αυτό το {object};",
"import_running": "Εισαγωγή σε εξέλιξη, παρακαλώ περιμένετε!",
"all_fields_optional": "Όλα τα πεδία είναι προαιρετικά και μπορούν να μη συμπληρωθούν.",
"convert_internal": "Μετατροπή σε εσωτερική συνταγή",
"show_only_internal": "Εμφάνιση μόνο εσωτερικών συνταγών",
"show_split_screen": "Χωρισμένη οθόνη",
"Log_Recipe_Cooking": "Καταγραφή εκτέλεσης συνταγής",
"External_Recipe_Image": "Εξωτερική εικόνα συνταγής",
"Add_to_Shopping": "Προσθήκη στις αγορές",
"Add_to_Plan": "Προσθήκη στο πρόγραμμα",
"Step_start_time": "Χρόνος αρχής βήματος",
"Sort_by_new": "Ταξινόμηση κατά νέο",
"Table_of_Contents": "Πίνακας περιεχομένων",
"Recipes_per_page": "Συνταγές ανά σελίδα",
"Show_as_header": "Εμφάνιση ως κεφαλίδα",
"Hide_as_header": "Απόκρυψη ως κεφαλίδα",
"Add_nutrition_recipe": "Προσθήκη διατροφικής αξίας στη συνταγή",
"Remove_nutrition_recipe": "Αφαίρεση διατροφικής αξίας από τη συνταγή",
"Copy_template_reference": "Αντιγραφή αναφοράς σε πρότυπο",
"per_serving": "ανά μερίδα",
"Save_and_View": "Αποθήκευση και προβολή",
"Manage_Books": "Διαχείριση βιβλίων",
"Meal_Plan": "Πρόγραμμα γευμάτων",
"Select_Book": "Επιλογή βιβλίου",
"Select_File": "Επιλογή αρχείου",
"Recipe_Image": "Εικόνα συνταγής",
"Import_finished": "Η εισαγωγή ολοκληρώθηκε",
"View_Recipes": "Προβολή συνταγών",
"Log_Cooking": "Καταγραφή μαγειρέματος",
"New_Recipe": "Νέα συνταγή",
"Url_Import": "Εισαγωγή Url",
"Reset_Search": "Επαναφορά αναζήτησης",
"Recently_Viewed": "Προβλήθηκαν πρόσφατα",
"Load_More": "Φόρτωση περισσότερων",
"New_Keyword": "Νέα λέξη-κλειδί",
"Delete_Keyword": "Διαγραφή λέξης-κλειδί",
"Edit_Keyword": "Τροποποίηση λέξης-κλειδί",
"Edit_Recipe": "Τροποποίηση συνταγής",
"Move_Keyword": "Μεταφορά λέξης-κλειδί",
"Merge_Keyword": "Συγχώνευση λέξης-κλειδί",
"Hide_Keywords": "Απόκρυψη λέξης-κλειδί",
"Hide_Recipes": "Απόκρυψη συνταγών",
"Move_Up": "Μετακίνηση πάνω",
"Move_Down": "Μετακίνηση κάτω",
"Step_Name": "Όνομα βήματος",
"Step_Type": "Είδος βήματος",
"Make_Header": "Δημιουργία κεφαλίδας",
"Make_Ingredient": "Δημιουργία υλικού",
"Amount": "Ποσότητα",
"Enable_Amount": "Ενεργοποίηση ποσότητας",
"Disable_Amount": "Απενεργοποίηση ποσότητας",
"Ingredient Editor": "Επεξεργαστής συστατικών",
"Description_Replace": "Αλλαγή περιγραφής",
"Instruction_Replace": "Αλλαγή οδηγίας",
"Auto_Sort": "Αυτόματη ταξινόμηση",
"Auto_Sort_Help": "Μετακίνηση όλων των υλικών στο καταλληλότερο βήμα.",
"Private_Recipe": "Ιδιωτική συνταγή",
"Private_Recipe_Help": "Η συνταγή είναι ορατή μόνο σε εσάς και στα άτομα με τα οποία την μοιράζεστε.",
"reusable_help_text": "Ο σύνδεσμος πρόσκλησης μπορεί να χρησιμοποιηθεί από πολλαπλούς χρήστες.",
"open_data_help_text": "Μέσω του project Tandoor Open Data η κοινότητα παρέχει δεδομένα για το Tandoor. Αυτό το πεδίο συμπληρώνεται αυτόματα κατά την εισαγωγή του και επιτρέπει ενημερώσεις στο μέλλον.",
"Open_Data_Slug": "Αναγνωριστικό (Slug) Open Data",
"Open_Data_Import": "Εισαγωγή ανοιχτών δεδομένων",
"Data_Import_Info": "Βελτιώστε τον χώρο και τη συλλογή συνταγών σας κάνοντας εισαγωγή μιας λίστας από φαγητά, μονάδες μέτρησης κ.α., επιμελημένη από την κοινότητα.",
"Update_Existing_Data": "Ενημέρωση υπαρχόντων δεδομένων",
"Use_Metric": "Χρήση μετρικών μονάδων μέτρησης",
"Learn_More": "Μάθετε περισσότερα",
"converted_unit": "Μετατρεπόμενη μονάδα μέτρησης",
"converted_amount": "Μετατρεπόμενη ποσότητα",
"base_unit": "Βασική μονάδα μέτρησης",
"base_amount": "Βασική ποσότητα",
"Datatype": "Τύπος δεδομένων",
"Number of Objects": "Αριθμός αντικειμένων",
"Add_Step": "Προσθήκη βήματος",
"Keywords": "Λέξεις κλειδιά",
"Books": "Βιβλία",
"Proteins": "Πρωτεΐνες",
"Fats": "Λιπαρά",
"Carbohydrates": "Υδατάνθρακες",
"Calories": "Θερμίδες",
"Energy": "Ενέργεια",
"Nutrition": "Διατροφική αξία",
"Date": "Ημερομηνία",
"Share": "Κοινοποίηση",
"Automation": "Αυτοματισμός",
"Parameter": "Παράμετρος",
"Export": "Εξαγωγή",
"Copy": "Αντιγραφή",
"Rating": "Βαθμολογία",
"Close": "Κλείσιμο",
"Cancel": "Ακύρωση",
"Link": "Σύνδεσμος",
"Add": "Προσθήκη",
"New": "Νέο",
"Note": "Σημείωση",
"Success": "Επιτυχία",
"Failure": "Αποτυχία",
"Protected": "Προστατευμένο",
"Ingredients": "Υλικά",
"Supermarket": "Supermarket",
"Categories": "Κατηγορίες",
"Category": "Κατηγορία",
"Selected": "Επιλεγμένο",
"min": "ελάχ",
"Servings": "Μερίδες",
"Waiting": "Αναμονή",
"Preparation": "Προετοιμασία",
"External": "Εξωτερική",
"Size": "Μέγεθος",
"Files": "Αρχεία",
"File": "Αρχείο",
"Edit": "Τροποποίηση",
"Image": "Εικόνα",
"Delete": "Διαγραφή",
"Open": "Άνοιγμα",
"Ok": "ΟΚ",
"Save": "Αποθήκευση",
"Step": "Βήμα",
"Search": "Αναζήτηση",
"Import": "Εισαγωγή",
"Print": "Εκτύπωση",
"Settings": "Ρυθμίσεις",
"or": "ή",
"and": "και",
"Information": "Πληροφορίες",
"Download": "Λήψη",
"Create": "Δημιουργία",
"Search Settings": "Επιλογές αναζήτησης",
"View": "Προβολή",
"Recipes": "Συνταγές",
"Move": "Μετακίνηση",
"Merge": "Συγχώνευση",
"Parent": "Γονέας",
"Copy Link": "Αντιγραφή συνδέσμου",
"Copy Token": "Αντιγραφή token",
"delete_confirmation": "Είστε σίγουροι ότι θέλετε να διαγράψετε το {source};",
"move_confirmation": "Μετακίνηση του <i>{child}</i> στο γονέα <i>{parent}</i>",
"merge_confirmation": "Αντικατάσταση του <i>{source}</i> με το <i>{target}</i>",
"create_rule": "και δημιουργία αυτοματισμού",
"move_selection": "Επιλέξτε έναν γονέα {type} για να μεταφέρετε το {source} σε αυτόν.",
"merge_selection": "Αντικατάσταση όλων των εμφανίσεων του {source} με το επιλεγμένο {type}.",
"Root": "Ρίζα",
"Ignore_Shopping": "Παράλειψη αγορών",
"Shopping_Category": "Κατηγορία αγορών",
"Shopping_Categories": "Κατηγορίες αγορών",
"Edit_Food": "Τροποποίηση φαγητού",
"Move_Food": "Μετακίνηση φαγητού",
"New_Food": "Νέο φαγητό",
"Hide_Food": "Απόκρυψη φαγητού",
"Food_Alias": "Ψευδώνυμο φαγητού",
"Unit_Alias": "Ψευδώνυμο μονάδας μέτρησης",
"Keyword_Alias": "Ψευδώνυμο λέξης-κλειδί",
"Delete_Food": "Διαγραφή φαγητού",
"No_ID": "Το ID δεν βρέθηκε, αδύνατη η διαγραφή.",
"Meal_Plan_Days": "Μελλοντικά προγράμματα γευμάτων",
"merge_title": "Συγχώνευση {type}",
"move_title": "Μετακίνηση {type}",
"Food": "Φαγητό",
"Property": "Ιδιότητα",
"Conversion": "Μετατροπή",
"Original_Text": "Αρχικό κείμενο",
"Recipe_Book": "Βιβλίο συνταγών",
"del_confirmation_tree": "Θέλετε σίγουρα να διαγράψετε το {source} και όλα τα παιδιά του;",
"delete_title": "Διαγραφή {type}",
"create_title": "Νέο {type}",
"edit_title": "Τροποποίηση {type}",
"Name": "Όνομα",
"Properties": "Ιδιότητες",
"Type": "Είδος",
"Description": "Περιγραφή",
"Recipe": "Συνταγή",
"tree_root": "Ρίζα του δέντρου",
"Icon": "Εικονίδιο",
"Unit": "Μονάδα μέτρησης",
"Decimals": "Δεκαδικά",
"Default_Unit": "Προεπιλεγμένη μονάδα μέτρησης",
"No_Results": "Δεν υπάρχουν αποτελέσματα",
"New_Unit": "Νέα μονάδα μέτρησης",
"Create_New_Shopping Category": "Δημιουργία νέας κατηγορίας αγορών",
"Create_New_Food": "Προσθήκη νέου φαγητού",
"Create_New_Keyword": "Προσθήκη νέας λέξης-κλειδί",
"Create_New_Unit": "Προσθήκη νέας μονάδας μέτρησης",
"Create_New_Meal_Type": "Προσθήκη νέου είδους γεύματος",
"Create_New_Shopping_Category": "Προσθήκη νέας κατηγορίας αγορών",
"and_up": "και πάνω",
"and_down": "και κάτω",
"Instructions": "Οδηγίες",
"Unrated": "Χωρίς βαθμολογία",
"Automate": "Αυτοματοποίηση",
"Empty": "Κενό",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Time": "Χρόνος",
"Text": "Κείμενο",
"Shopping_list": "Λίστα αγορών",
"Added_by": "Προστέθηκε από",
"Added_on": "Προστέθηκε στις",
"AddToShopping": "Προσθήκη στη λίστα αγορών",
"IngredientInShopping": "Αυτό το υλικό είναι στη λίστα αγορών.",
"NotInShopping": "Το φαγητό { food} δεν είναι στη λίστα αγορών σας.",
"OnHand": "Τώρα διαθέσιμα",
"FoodOnHand": "Έχετε το φαγητό {food} διαθέσιμο.",
"FoodNotOnHand": "Δεν έχετε το φαγητό {food} διαθέσιμο.",
"Undefined": "Απροσδιόριστο",
"Create_Meal_Plan_Entry": "Δημιουργία εγγραφής στο πρόγραμμα γευμάτων",
"Edit_Meal_Plan_Entry": "Τροποποίηση εγγραφής στο πρόγραμμα γευμάτων",
"Title": "Τίτλος",
"Week": "Εβδομάδα",
"Month": "Μήνας",
"Year": "Έτος",
"Planner": "Σχεδιαστής",
"Planner_Settings": "Επιλογές σχεδιαστή",
"Period": "Περίοδος",
"Plan_Period_To_Show": "Εμφάνιση εβδομάδων, μηνών ή ετών",
"Periods": "Περίοδοι",
"Plan_Show_How_Many_Periods": "Πόσες περίοδοι να εμφανίζονται",
"Starting_Day": "Πρώτη μέρα της εβδομάδας",
"Meal_Types": "Είδη γευμάτων",
"Meal_Type": "Είδος γεύματος",
"New_Entry": "Νέα εγγραφή",
"Clone": "Αντιγραφή",
"Drag_Here_To_Delete": "Σύρετε εδώ για διαγραφή",
"Meal_Type_Required": "Το είδος του γεύματος είναι απαραίτητο",
"Title_or_Recipe_Required": "Η επιλογή τίτλου ή συνταγής είναι απαραίτητη",
"Color": "Χρώμα",
"New_Meal_Type": "Νέο είδος γεύματος",
"Use_Fractions": "Χρήση κλασμάτων",
"Use_Fractions_Help": "Αυτόματη μετατροπή δεκαδικών σε κλάσματα κατά την προβολή μιας συνταγής.",
"AddFoodToShopping": "Προσθήκη του φαγητού {food} στη λίστα αγορών σας",
"RemoveFoodFromShopping": "Αφαίρεση του φαγητού {food} από τη λίστα αγορών σας",
"DeleteShoppingConfirm": "Θέλετε σίγουρα να αφαιρέσετε τα {food} από τη λίστα αγορών;",
"IgnoredFood": "Το φαγητό {food} έχει ρυθμιστεί να αγνοεί τις αγορές.",
"Add_Servings_to_Shopping": "Προσθήκη {servings} μερίδων στις αγορές",
"Week_Numbers": "Αριθμοί εδομάδων",
"Show_Week_Numbers": "Εμφάνιση αριθμών εβδομάδων;",
"Export_As_ICal": "Εξαγωγή της τρέχουσας περιόδου σε μορφή iCal",
"Export_To_ICal": "Εξαγωγή .ics",
"Cannot_Add_Notes_To_Shopping": "Δεν είναι δυνατή η προσθήκη σημειώσεων στη λίστα αγορών",
"Added_To_Shopping_List": "Προστέθηκε στη λίστα αγορών",
"Shopping_List_Empty": "Η λίστα αγορών σας είναι κενή, μπορείτε να προσθέσετε αντικείμενα από το μενού μιας εγγραφής στο πρόγραμμα γευμάτων (δεξί κλικ στην κάρτα ή αριστερό κλικ στο εικονίδιο του μενού)",
"Next_Period": "Επόμενη περίοδος",
"Previous_Period": "Προηγούμενη περίοδος",
"Current_Period": "Τρέχουσα περίοδος",
"Next_Day": "Επόμενη μέρα",
"Previous_Day": "Προηγούμενη μέρα",
"Inherit": "Κληρονόμηση",
"InheritFields": "Κληρονόμηση τιμών πεδίων",
"FoodInherit": "Πεδία φαγητών που κληρονομούνται",
"ShowUncategorizedFood": "Εμφάνιση απροσδιόριστων",
"GroupBy": "Ομαδοποίηση κατά",
"Language": "Γλώσσα",
"Theme": "Θέμα",
"SupermarketCategoriesOnly": "Μόνο κατηγορίες supermarket",
"MoveCategory": "Μετακίνηση σε: ",
"CountMore": "...+{count} περισσότερα",
"IgnoreThis": "Να μην προστίθεται αυτόματα το φαγητό {food} στις αγορές",
"DelayFor": "Καθυστέρηση για {hours} ώρες",
"Warning": "Προειδοποίηση",
"NoCategory": "Δεν έχει επιλεγεί κατηγορία.",
"InheritWarning": "To φαγητό {food} έχει ρυθμιστεί να κληρονομεί, οι αλλαγές μπορεί να μην διατηρηθούν.",
"ShowDelayed": "Εμφάνιση αντικειμένων που έχουν καθυστερήσει",
"Completed": "Ολοκληρωμένο",
"OfflineAlert": "Είστε εκτός σύνδεσης, η λίστα αγορών μπορεί να μην συγχρονιστεί.",
"shopping_share": "Κοινοποίηση λίστας αγορών",
"shopping_auto_sync": "Αυτόματος συγχρονισμός",
"one_url_per_line": "Ένα URL ανά γραμμή",
"mealplan_autoadd_shopping": "Αυτόματη προσθήκη προγράμματος γευμάτων",
"mealplan_autoexclude_onhand": "Εξαίρεση διαθέσιμων φαγητών",
"mealplan_autoinclude_related": "Προσθήκη σχετικών συνταγών",
"default_delay": "Προεπιλεγμένες ώρες καθυστέρησης",
"plan_share_desc": "Οι νέες εγγραφές στο πρόγραμμα γευμάτων θα κοινοποιηθούν αυτόματα με τους επιλεγμένους χρήστες.",
"shopping_share_desc": "Οι χρήστες θα μπορούν να δουν όλα τα αντικείμενα που τοποθετείτε στη λίστα αγορών σας. Πρέπει να σας προσθέσουν για να δείτε τα αντικείμενα στη λίστα τους.",
"shopping_auto_sync_desc": "Θέτοντας το στο 0 θα απενεργοποιηθεί ο αυτόματος συγχρονισμός. Κατά την προβολή μιας λίστας, η λίστα ενημερώνεται ανά τα ορισμένα δευτερόλεπτα, ώστε να συγχρονιστούν τυχόν αλλαγές που έχουν κάνει άλλοι χρήστες. Η λειτουργία είναι χρήσιμη αν πραγματοποιούν αγορές πολλαπλοί χρήστες αλλά χρησιμοποιεί επιπλέον δεδομένα.",
"mealplan_autoadd_shopping_desc": "Αυτόματη προθήκη συστατικών του προγράμματος γευμάτων στη λίστα αγορών.",
"mealplan_autoexclude_onhand_desc": "Κατά την προσθήκη ενός προγράμματος γευμάτων στη λίστα αγορών (χειροκίνητα ή αυτόματα), εξαίρεσε τυχόν υλικά που είναι διαθέσιμα.",
"mealplan_autoinclude_related_desc": "Κατά την προσθήκη ενός προγράμματος γευμάτων στη λίστα αγορών (χειροκίνητα ή αυτόματα), συμπερίλαβε όλες τις σχετικές συνταγές.",
"default_delay_desc": "Προεπιλεγμένος αριθμός ωρών καθυστέρησης μια εγγραφής στην λίστα αγορών.",
"filter_to_supermarket": "Ταξινόμηση ανά Supermarket",
"Coming_Soon": "Σύντομα διαθέσιμο",
"Auto_Planner": "Αυτόματος προγραμματιστής",
"New_Cookbook": "Νέο βιβλίο μαγειρικής",
"Hide_Keyword": "Απόκρυψη λέξεων-κλειδί",
"Hour": "Ώρα",
"Hours": "Ώρες",
"Day": "Ημέρα",
"Days": "Ημέρες",
"Second": "Δευτερόλεπτο",
"Seconds": "Δευτερόλεπτα",
"Clear": "Εκκαθάριση",
"Users": "Χρήστες",
"Invites": "Προσκλήσεις",
"err_move_self": "Δεν είναι δυνατή η μετακίνηση ενός αντικειμένου στον εαυτό του",
"nothing": "Καμία δράση",
"err_merge_self": "Δεν είναι δυνατή η συγχώνευση ενός αντικειμένου με τον εαυτό του",
"show_sql": "Εμφάνιση SQL",
"filter_to_supermarket_desc": "Αυτόματο φιλτράρισμα λίστας αγορών ώστε να περιέχει μόνο κατηγορίες για το επιλεγμένο supermarket.",
"CategoryName": "Όνομα κατηγορίας",
"SupermarketName": "Όνομα supermarket",
"CategoryInstruction": "Σύρετε κατηγορίες για να αλλάξετε τη σειρά με την οποία εμφανίζονται στη λίστα αγορών.",
"shopping_recent_days_desc": "Ημέρες πρόσφατων εγγραφών στη λίστα αγορών που προβάλλονται.",
"shopping_recent_days": "Πρόσφατες ημέρες",
"download_pdf": "Λήψη PDF",
"download_csv": "Λήψη CSV",
"csv_delim_help": "Χαρακτήρας διαχωρισμού για εξαγωγή σε CSV.",
"csv_delim_label": "Χαρακτήρας διαχωρισμού CSV",
"SuccessClipboard": "Η λίστα αγορών αντιγράφηκε στο πρόχειρο",
"copy_to_clipboard": "Αντιγραφή στο πρόχειρο",
"csv_prefix_help": "Πρόθεμα που προστίθεται κατά την αντιγραφή της λίστας στο πρόχειρο (clipboard).",
"csv_prefix_label": "Πρόθεμα λίστας",
"copy_markdown_table": "Αντιγραφή ως πίνακας Markdown",
"in_shopping": "Στη λίστα αγορών",
"DelayUntil": "Καθυστέρηση μέχρι",
"Pin": "Καρφίτσωμα",
"Unpin": "Αφαίρεση καρφιτσώματος",
"PinnedConfirmation": "Η συνταγή {recipe} έχει καρφιτσωθεί.",
"UnpinnedConfirmation": "Η συνταγή {recipe} αφαιρέθηκε από τις καρφιτσωμένες.",
"mark_complete": "Σήμανση ως ολοκληρωμένο",
"QuickEntry": "Γρήγορη καταχώρηση",
"shopping_add_onhand_desc": "Χαρακτηρισμός ενός τροφίμου ως 'Διαθέσιμο' όταν τσεκαριστεί στη λίστα αγορών.",
"shopping_add_onhand": "Αυτόματα διαθέσιμο",
"related_recipes": "Σχετικές συνταγές",
"today_recipes": "Συνταγές της ημέρας",
"sql_debug": "Αποσφαλμάτωση SQL",
"remember_search": "Αποθήκευση αναζήτησης",
"remember_hours": "Ώρες αποθήκευσης",
"tree_select": "Χρήση επιλογής δέντρου",
"OnHand_help": "Το φαγητό είναι διαθέσιμο και δε θα προστεθεί αυτόματα στη λίστα αγορών. Η διαθεσιμότητα ενός φαγητού είναι κοινή για όλους τους χρήστες των αγορών.",
"ignore_shopping_help": "Το φαγητό να μην προστίθεται στη λίστα αγορών (π.χ. νερό)",
"shopping_category_help": "Τα supermarket μπορούν να διαταχθούν και φιλτραριστούν ανάλογα με την κατηγορία αγορών σύμφωνα με την διάταξη των διαδρόμων τους.",
"food_recipe_help": "Η σύνδεση μιας συνταγής εδώ θα συμπεριλάβει τη συνταγή που συνδέεται σε κάθε άλλη συνταγή που χρησιμοποιεί αυτό το φαγητό",
"Foods": "Φαγητά",
"Account": "Λογαριασμός",
"Cosmetic": "Κοσμητικό",
"API": "API",
"enable_expert": "Ενεργοποίηση λειτουργίας για προχωρημένους",
"expert_mode": "Λειτουργία για προχωρημένους",
"simple_mode": "Απλή λειτουργία",
"advanced": "Για προχωρημένους",
"fields": "Πεδία",
"show_keywords": "Εμφάνιση λέξεων-κλειδί",
"show_foods": "Εμφάνιση φαγητών",
"show_books": "Εμφάνιση βιβλίων",
"show_rating": "Εμφάνιση βαθμολογίας",
"show_units": "Εμφάνιση μονάδων μέτρησης",
"show_filters": "Εμφάνιση φίλτρων",
"not": "όχι",
"save_filter": "Αποθήκευση φίλτρου",
"filter_name": "Όνομα φίλτρου",
"left_handed": "Έκδοση για αριστερόχειρες",
"left_handed_help": "Θα βελτιστοποιήσει το περιβάλλον χρήστη για χρήση με το αριστερό χέρι.",
"Custom Filter": "Προσαρμοσμένο φίλτρο",
"shared_with": "Διαμοιράζεται με",
"sort_by": "Ταξινόμηση κατά",
"asc": "Αύξουσα",
"desc": "Φθίνουσα",
"date_viewed": "Προβλήθηκαν τελευταία",
"last_cooked": "Μαγειρεύτηκαν τελευταία",
"times_cooked": "Φορές που έχει μαγειρευτεί",
"date_created": "Ημερομηνία δημιουργίας",
"show_sortby": "Εμφάνιση ταξινόμησης κατά",
"search_rank": "Σειρά αναζήτησης",
"make_now": "Άμεσα διαθέσιμη",
"recipe_filter": "Φίλτρο συνταγών",
"book_filter_help": "Συμπερίλαβε συνταγές από το φίλτρο μαζί με αυτές που έχουν ανατεθεί χειροκίνητα.",
"review_shopping": "Ανασκόπηση εγγραφών στις αγορές πριν την αποθήκευση",
"view_recipe": "Εμφάνιση συνταγής",
"copy_to_new": "Αντιγραφή σε νέα συνταγή",
"recipe_name": "Όνομα συνταγής",
"paste_ingredients_placeholder": "Κάντε επικόλληση της λίστας υλικών εδώ...",
"paste_ingredients": "Επικόλληση υλικών",
"ingredient_list": "Λίστα υλικών",
"explain": "Επεξήγηση",
"filter": "Φίλτρο",
"Website": "Ιστοσελίδα",
"App": "Εφαρμογή",
"Message": "Μήνυμα",
"Bookmarklet": "Bookmarklet",
"Sticky_Nav": "Κολλητική πλοήγηση",
"Sticky_Nav_Help": "Μόνιμη εμφάνιση του μενού πλοήγησης στο πάνω μέρος της οθόνης.",
"Nav_Color": "Χρώμα πλοήγησης",
"Nav_Color_Help": "Αλλαγή χρώματος πλοήγησης.",
"Use_Kj": "Χρήση kJ αντί για kcal",
"Comments_setting": "Εμφάνιση σχολίων",
"click_image_import": "Κάντε κλικ στην εικόνα που θέλετε να εισάγετε για αυτή τη συνταγή",
"no_more_images_found": "Δεν βρέθηκαν επιπλέον εικόνες στην ιστοσελίδα.",
"import_duplicates": "Για να αποφευχθεί η δημιουργία διπλών συνταγών αγνοούνται συνταγές που έχουν ίδιο όνομα με υπάρχουσες. Τσεκάρετε το κουτί για να τις εισάγετε όλες.",
"paste_json": "Κάντε επικόλληση κώδικα html ή json για να εισάγετε τη συνταγή.",
"Click_To_Edit": "Κάντε κλικ για τροποποίηση",
"search_no_recipes": "Δεν βρέθηκαν συνταγές!",
"search_import_help_text": "Εισαγωγή συνταγής από μια ιστοσελίδα ή εφαρμογή.",
"search_create_help_text": "Δημιουργία νέας συνταγής απευθείας στο Tandoor.",
"warning_duplicate_filter": "Προειδοποίηση: Λόγω τεχνικών περιορισμών η ύπαρξη πολλαπλών φίλτρων με τους ίδιους συνδυασμούς (και/ή/όχι) μπορεί να οδηγήσει σε απρόσμενα αποτελέσματα.",
"reset_children": "Επαναφορά κληρονομικότητας παιδιών",
"reset_children_help": "Αντικατάσταση όλων των παιδιών με τιμές από τα επιλεγμένα πεδία. Τα πεδία που κληρονομούνται από τα παιδιά θα οριστούν να \"Κληρονομούν πεδία\" εκτός και αν έχει ενεργοποιηθεί η επιλογή \"Τα παιδιά κληρονομούν τα πεδία\".",
"reset_food_inheritance": "Επαναφορά κληρονομικότητας",
"reset_food_inheritance_info": "Επαναφορά όλων των φαγητών στα προεπιλεγμένα κληρονομούμενα πεδία και τις τιμές των γονέων τους.",
"substitute_help": "Τα υποκατάστατα εξετάζονται όταν αναζητούνται συνταγής που μπορούν να γίνουν με τα διαθέσιμα υλικά.",
"substitute_siblings_help": "Όλα τα φαγητά που μοιράζονται έναν γονέα αυτού του φαγητού θεωρούνται υποκατάστατα.",
"substitute_children_help": "Όλα τα φαγητά που είναι παιδιά αυτού του φαγητού θεωρούνται υποκατάστατα.",
"substitute_siblings": "Αδέρφια υποκατάστατα",
"substitute_children": "Παιδιά υποκατάστατα",
"SubstituteOnHand": "Έχετε διαθέσιμο ένα υποκατάστατο.",
"ChildInheritFields": "Τα παιδιά κληρονομούν τα πεδία",
"ChildInheritFields_help": "Τα παιδιά θα κληρονομούν αυτά τα πεδία από προεπιλογή.",
"InheritFields_help": "Οι τιμές αυτών των πεδίων θα κληρονομηθούν από τον γονέα (Εξαίρεση: οι κενές κατηγορίες αγορών δεν κληρονομούνται)",
"show_ingredient_overview": "Εμφάνιση λίστας υλικών στην αρχή της συνταγής.",
"Ingredient Overview": "Σύνοψη υλικών",
"last_viewed": "Προβλήθηκαν τελευταία",
"created_on": "Δημιουργήθηκε στις",
"updatedon": "Ενημερώθηκε στις",
"Imported_From": "Πηγή",
"advanced_search_settings": "Προχωρημένες ρυθμίσεις αναζήτησης",
"nothing_planned_today": "Δεν έχετε τίποτα προγραμματισμένο για σήμερα!",
"no_pinned_recipes": "Δεν έχετε καρφιτσωμένες συνταγές!",
"Planned": "Προγραμματισμένα",
"Pinned": "Καρφιτσωμένα",
"Imported": "Εισαγμένα",
"Quick actions": "Γρήγηορες δράσεις",
"Ratings": "Βαθμολογίες",
"Internal": "Εσωτερική",
"Units": "Μονάδες μέτρησης",
"Manage_Emails": "Διαχείριση email",
"Change_Password": "Αλλαγή κωδικού πρόσβασης",
"Social_Authentication": "Ταυτοποίηση μέσω κοινωνικών δικτύων",
"Random Recipes": "Τυχαίες συνταγές",
"parameter_count": "Παράμετρος {count}",
"select_keyword": "Επιλογή λέξης-κλειδί",
"add_keyword": "Προσθήκη λέξης-κλειδί",
"select_file": "Επιλογή αρχείου",
"select_recipe": "Επιλογή συνταγής",
"select_unit": "Επιλογή μονάδας μέτρησης",
"select_food": "Επιλογή φαγητού",
"remove_selection": "Αφαίρεση επιλογής",
"empty_list": "Η λίστα είναι άδεια.",
"Select": "Επιλογή",
"Supermarkets": "Supermarket",
"User": "Χρήστης",
"Username": "Όνομα χρήστη",
"First_name": "Όνομα",
"Last_name": "Επίθετο",
"Keyword": "Λέξη κλειδί",
"Advanced": "Για προχωρημένους",
"Page": "Σελίδα",
"Single": "Ενικός",
"Multiple": "Πολλαπλές",
"Reset": "Επαναφορά",
"Disabled": "Απενεροποιημένο",
"Disable": "Απενεργοποίηση",
"Options": "Επιλογές",
"Create Food": "Δημιουργία φαγητού",
"create_food_desc": "Δημιουργία φαγητού και δημιουργία συνδέσμου σε αυτή τη συνταγή.",
"additional_options": "Επιπλέον επιλογές",
"Importer_Help": "Περισσότερες πληροφορίες και βοήθεια για αυτό το πρόγραμμα εισαγωγής:",
"Documentation": "Τεκμηρίωση",
"Select_App_To_Import": "Επιλέξτε μια εφαρμογή από την οποία θα γίνει εισαγωγή",
"Import_Supported": "Υποστηρίζεται εισαγωγή",
"Export_Supported": "Υποστηρίζεται εξαγωγή",
"Import_Not_Yet_Supported": "Η εισαγωγή δεν υποστηρίζεται ακόμη",
"Export_Not_Yet_Supported": "Η εξαγωγή δεν υποστηρίζεται ακόμη",
"Import_Result_Info": "Έγινε εισαγωγή {imported} από τις {total} συνταγές",
"Recipes_In_Import": "Συνταγές στο αρχείο εισαγωγής",
"Toggle": "Εναλλαγή",
"total": "σύνολο",
"Import_Error": "Συνέβη ένα σφάλμα κατά την εισαγωγή. Για να το δείτε, εμφανίστε τις λεπτομέρειες στο κάτω μέρος της σελίδας.",
"Warning_Delete_Supermarket_Category": "Η διαγραφή μιας κατηγορίας supermarket θα διαγράψει και όλες τις σχέσεις της με φαγητά. Είστε σίγουροι;",
"New_Supermarket": "Δημιουργία νέου supermarket",
"New_Supermarket_Category": "Δημιουργία νέας κατηγορίας supermarket",
"Are_You_Sure": "Είστε σίγουροι;",
"Valid Until": "Ισχύει έως",
"Split_All_Steps": "Διαχωρισμός όλων των γραμμών σε χωριστά βήματα.",
"Combine_All_Steps": "Συγχώνευση όλων των βημάτων σε ένα πεδίο.",
"Plural": "Πληθυντικός",
"plural_short": "πληθυντικός",
"Use_Plural_Unit_Always": "Να χρησιμοποιείται πάντα ο πληθυντικός για τη μονάδα μέτρησης",
"Use_Plural_Unit_Simple": "Να επιλέγεται δυναμικά ο πληθυντικός για τη μονάδα μέτρησης",
"Use_Plural_Food_Always": "Να χρησιμοποιείται πάντα ο πληθυντικός για το φαγητό",
"Use_Plural_Food_Simple": "Να επιλέγεται δυναμικά ο πληθυντικός για το φαγητό",
"plural_usage_info": "Χρήση του πληθυντικού για τις μονάδες μέτρησης και τα φαγητά μέσα σε αυτόν τον χώρο.",
"Create Recipe": "Δημιουργία συνταγής",
"Import Recipe": "Εισαγωγή συνταγής",
"Welcome": "Καλώς ήρθατε",
"kg": "κιλό [kg] (μετρικό, βάρος)",
"l": "λίτρο [l] (μετρικό, όγκος)",
"gallon": "γαλόνι [gal] (ΗΠΑ, όγκος)",
"imperial_fluid_ounce": "αυτοκρατορική υγρή ουγγιά [imp fl oz] (Ηνωμένο Βασίλειο, όγκος)",
"imperial_quart": "αυτοκρατορικό τέταρτο γαλονιού [imp qt] (Ηνωμένο Βασίλειο, όγκος)",
"imperial_tsp": "αυτοκρατορικό κουτάλι του γλυκού [imp tsp] (Ηνωμένο Βασίλειο, όγκος)",
"g": "γραμμάριο [g] (μετρικό, βάρος)",
"ounce": "ουγγιά [oz] (βάρος)",
"pound": "λίβρα (βάρος)",
"ml": "μιλιλίτρο [ml] (μετρικό, όγκος)",
"fluid_ounce": "υγρή ουγγιά [fl oz] (ΗΠΑ, όγκος)",
"pint": "πίντα [pt] (ΗΠΑ, όγκος)",
"quart": "τέταρτο γαλονιού (ΗΠΑ, όγκος)",
"tbsp": "κουτάλι της σούπας [tbsp] (ΗΠΑ, όγκος)",
"tsp": "κουτάλι του γλυκού [tsp] (ΗΠΑ, όγκος)",
"imperial_pint": "αυτοκρατορική πίντα [imp pt] (Ηνωμένο Βασίλειο, όγκος)",
"imperial_gallon": "αυτοκρατορικό γαλόνι [imp gal] (Ηνωμένο Βασίλειο, όγκος)",
"imperial_tbsp": "αυτοκρατορικό κουτάλι της σούπας [imp tbsp] (Ηνωμένο Βασίλειο, όγκος)",
"Choose_Category": "Επιλογή κατηγορίας",
"Back": "Πίσω"
}

View File

@ -1,5 +1,5 @@
{
"warning_feature_beta": "This feature is currently in a BETA (testing) state. Please expect bugs and possibly breaking changes in the future (possibly loosing feature related data) when using this feature.",
"warning_feature_beta": "This feature is currently in a BETA (testing) state. Please expect bugs and possibly breaking changes in the future (possibly losing feature-related data) when using this feature.",
"err_fetching_resource": "There was an error fetching a resource!",
"err_creating_resource": "There was an error creating a resource!",
"err_updating_resource": "There was an error updating a resource!",
@ -14,9 +14,9 @@
"success_moving_resource": "Successfully moved a resource!",
"success_merging_resource": "Successfully merged a resource!",
"file_upload_disabled": "File upload is not enabled for your space.",
"recipe_property_info": "You can also add properties to foods to calculate them automatically based on your recipe!",
"warning_space_delete": "You can delete your space including all recipes, shopping lists, meal plans and whatever else you have created. This cannot be undone! Are you sure you want to do this ?",
"food_inherit_info": "Fields on food that should be inherited by default.",
"facet_count_info": "Show recipe counts on search filters.",
"step_time_minutes": "Step time in minutes",
"confirm_delete": "Are you sure you want to delete this {object}?",
"import_running": "Import running, please wait!",
@ -37,6 +37,7 @@
"Add_nutrition_recipe": "Add nutrition to recipe",
"Remove_nutrition_recipe": "Delete nutrition from recipe",
"Copy_template_reference": "Copy template reference",
"per_serving": "per servings",
"Save_and_View": "Save & View",
"Manage_Books": "Manage Books",
"Meal_Plan": "Meal Plan",
@ -76,6 +77,19 @@
"Private_Recipe": "Private Recipe",
"Private_Recipe_Help": "Recipe is only shown to you and people its shared with.",
"reusable_help_text": "Should the invite link be usable for more than one user.",
"open_data_help_text": "The Tandoor Open Data project provides community contributed data for Tandoor. This field is filled automatically when importing it and allows updates in the future.",
"Open_Data_Slug": "Open Data Slug",
"Open_Data_Import": "Open Data Import",
"Data_Import_Info": "Enhance your Space by importing a community curated list of foods, units and more to improve your recipe collection.",
"Update_Existing_Data": "Update Existing Data",
"Use_Metric": "Use Metric Units",
"Learn_More": "Learn More",
"converted_unit": "Converted Unit",
"converted_amount": "Converted Amount",
"base_unit": "Base Unit",
"base_amount": "Base Amount",
"Datatype": "Datatype",
"Number of Objects": "Number of Objects",
"Add_Step": "Add Step",
"Keywords": "Keywords",
"Books": "Books",
@ -86,6 +100,8 @@
"Energy": "Energy",
"Nutrition": "Nutrition",
"Date": "Date",
"StartDate": "Start Date",
"EndDate": "End Date",
"Share": "Share",
"Automation": "Automation",
"Parameter": "Parameter",
@ -98,6 +114,7 @@
"Add": "Add",
"New": "New",
"Note": "Note",
"Alignment": "Alignment",
"Success": "Success",
"Failure": "Failure",
"Protected": "Protected",
@ -133,6 +150,7 @@
"Search Settings": "Search Settings",
"View": "View",
"Recipes": "Recipes",
"Welcome": "Welcome",
"Move": "Move",
"Merge": "Merge",
"Parent": "Parent",
@ -161,6 +179,8 @@
"merge_title": "Merge {type}",
"move_title": "Move {type}",
"Food": "Food",
"Property": "Property",
"Conversion": "Conversion",
"Original_Text": "Original Text",
"Recipe_Book": "Recipe Book",
"del_confirmation_tree": "Are you sure that you want to delete {source} and all of it's children?",
@ -168,6 +188,7 @@
"create_title": "New {type}",
"edit_title": "Edit {type}",
"Name": "Name",
"Properties": "Properties",
"Type": "Type",
"Description": "Description",
"Recipe": "Recipe",
@ -299,6 +320,7 @@
"CategoryName": "Category Name",
"SupermarketName": "Supermarket Name",
"CategoryInstruction": "Drag categories to change the order categories appear in shopping list.",
"OrderInformation": "Objects are ordered from small to large numbers.",
"shopping_recent_days_desc": "Days of recent shopping list entries to display.",
"shopping_recent_days": "Recent Days",
"download_pdf": "Download PDF",
@ -350,6 +372,10 @@
"filter_name": "Filter Name",
"left_handed": "Left-handed mode",
"left_handed_help": "Will optimize the UI for use with your left hand.",
"show_step_ingredients_setting": "Show Ingredients Next To Recipe Steps",
"show_step_ingredients_setting_help": "Add ingredients table next to recipe steps. Applies at creation time. Can be overridden in the edit recipe view.",
"show_step_ingredients": "Show Step Ingredients",
"hide_step_ingredients": "Hide Step Ingredients",
"Custom Filter": "Custom Filter",
"shared_with": "Shared With",
"sort_by": "Sort By",
@ -406,6 +432,7 @@
"ChildInheritFields": "Children Inherit Fields",
"ChildInheritFields_help": "Children will inherit these fields by default.",
"InheritFields_help": "The values of these fields will be inherited from parent (Exception: blank shopping categories are not inherited)",
"show_ingredients_table": "Display a table of the ingredients next to the step's text",
"show_ingredient_overview": "Display a list of all ingredients at the start of the recipe.",
"Ingredient Overview": "Ingredient Overview",
"last_viewed": "Last Viewed",
@ -463,21 +490,48 @@
"Import_Result_Info": "{imported} of {total} recipes were imported",
"Recipes_In_Import": "Recipes in your import file",
"Toggle": "Toggle",
"total": "total",
"Import_Error": "An Error occurred during your import. Please expand the Details at the bottom of the page to view it.",
"Warning_Delete_Supermarket_Category": "Deleting a supermarket category will also delete all relations to foods. Are you sure?",
"New_Supermarket": "Create new supermarket",
"New_Supermarket_Category": "Create new supermarket category",
"Are_You_Sure": "Are you sure?",
"Valid Until": "Valid Until",
"Split_All_Steps": "Split all rows into seperate steps.",
"Split_All_Steps": "Split all rows into separate steps.",
"Combine_All_Steps": "Combine all steps into a single field.",
"Plural": "Plural",
"plural_short": "plural",
"g": "gram [g] (metric, weight)",
"kg": "kilogram [kg] (metric, weight)",
"ounce": "ounce [oz] (weight)",
"pound": "pound (weight)",
"ml": "millilitre [ml] (metric, volume)",
"l": "litre [l] (metric, volume)",
"fluid_ounce": "fluid ounce [fl oz] (US, volume)",
"pint": "pint [pt] (US, volume)",
"quart": "quart [qt] (US, volume)",
"gallon": "gallon [gal] (US, volume)",
"tbsp": "tablespoon [tbsp] (US, volume)",
"tsp": "teaspoon [tsp] (US, volume)",
"imperial_fluid_ounce": "imperial fluid ounce [imp fl oz] (UK, volume)",
"imperial_pint": "imperial pint [imp pt] (UK, volume)",
"imperial_quart": "imperial quart [imp qt] (UK, volume)",
"imperial_gallon": "imperial gal [imp gal] (UK, volume)",
"imperial_tbsp": "imperial tablespoon [imp tbsp] (UK, volume)",
"imperial_tsp": "imperial teaspoon [imp tsp] (UK, volume)",
"Choose_Category": "Choose Category",
"Back": "Back",
"Use_Plural_Unit_Always": "Use plural form for unit always",
"Use_Plural_Unit_Simple": "Use plural form for unit dynamically",
"Use_Plural_Food_Always": "Use plural form for food always",
"Use_Plural_Food_Simple": "Use plural form for food dynamically",
"plural_usage_info": "Use the plural form for units and food inside this space.",
"Create Recipe": "Create Recipe",
"Import Recipe": "Import Recipe"
"Create Recipe": "Create Recipe",
"Import Recipe": "Import Recipe",
"Never_Unit": "Never Unit",
"Transpose_Words": "Transpose Words",
"Name_Replace":"Name Replace",
"Food_Replace":"Food Replace",
"Unit_Replace":"Unit Replace"
}

View File

@ -1,5 +1,5 @@
{
"warning_feature_beta": "Esta función está en fase BETA de pruebas. Podrían aparecer fallos y cambios importantes en un futuro (pudiendo perder la información) cuando uses esta función.",
"warning_feature_beta": "Esta función está en fase BETA de pruebas. Podrían aparecer fallos y cambios importantes en un futuro (pudiendo perder información relacionada con la funcionalidad) cuando uses esta función.",
"err_fetching_resource": "¡Hubo un error al obtener el recurso!",
"err_creating_resource": "¡Hubo un error al crear el recurso!",
"err_updating_resource": "¡Hubo un error al actualizar el recurso!",
@ -73,7 +73,7 @@
"Carbohydrates": "Carbohydratos",
"Calories": "Calorias",
"Energy": "Energia",
"Nutrition": "Nutricion",
"Nutrition": "Nutrición",
"Date": "Fecha",
"Share": "Compartir",
"Automation": "Automatización",
@ -107,7 +107,7 @@
"Image": "Imagen",
"Delete": "Borrar",
"Open": "Abrir",
"Ok": "Abrir",
"Ok": "Ok",
"Save": "Guardar",
"Step": "Paso",
"Search": "Buscar",
@ -147,7 +147,7 @@
"Meal_Plan_Days": "Planes de comida a futuro",
"merge_title": "Unificar {type}",
"move_title": "Mover {type}",
"Food": "Ingrediente",
"Food": "Alimento",
"Recipe_Book": "Libro de recetas",
"del_confirmation_tree": "Estas seguro que quieres eliminar {source} y todos sus elementos hijos?",
"delete_title": "Eliminar {type}",
@ -374,7 +374,7 @@
"Ratings": "",
"Internal": "",
"Units": "Unidades",
"Random Recipes": "",
"Random Recipes": "Recetas Aleatorias",
"parameter_count": "",
"select_keyword": "",
"add_keyword": "",
@ -415,11 +415,10 @@
"warning_space_delete": "Puedes eliminar tu espacio, incluyendo todas las recetas, listas de la compra, regímenes de comidas y cualquier otra cosa creada. ¡Esto no se puede deshacer! ¿Estás seguro de que quieres hacerlo?",
"Private_Recipe": "Receta Privada",
"Private_Recipe_Help": "La receta solo podrás verla tu y la gente con la que esta compartida.",
"reusable_help_text": "El link de invitación podrá ser usado por mas de un usuario",
"reusable_help_text": "El enlace de invitación podrá ser usado por más de un usuario.",
"Users": "Usuarios",
"Invites": "Invitaciones",
"food_inherit_info": "Campos que han de ser heredados por defecto.",
"facet_count_info": "Mostrar contadores de receta en los filtros de búsqueda.",
"Copy Link": "Copiar Enlace",
"Copy Token": "Copiar Token",
"Create_New_Shopping_Category": "Añadir nueva Categoría de Compras",
@ -452,5 +451,8 @@
"Auto_Sort": "Ordenar Automáticamente",
"Auto_Sort_Help": "Mueva todos los ingredientes al paso que mejor se adapte.",
"Unpin": "Desanclar",
"Amount": "Cantidad"
"Amount": "Cantidad",
"PinnedConfirmation": "{recipe} ha sido fijada.",
"recipe_property_info": "¡También puedes añadir propiedades a los alimentos para calcularlas automáticamente en función de tu receta!",
"per_serving": "por porción"
}

View File

@ -418,7 +418,6 @@
"Message": "Message",
"Sticky_Nav_Help": "Toujours afficher le menu de navigation en haut de lécran.",
"Combine_All_Steps": "Combiner toutes les étapes en un seul champ.",
"facet_count_info": "Afficher les compteurs de recette sur les filtres de recherche.",
"Decimals": "Décimales",
"plan_share_desc": "Les nouvelles entrées de menu de la semaine seront partagées automatiquement avec des utilisateurs sélectionnés.",
"Use_Kj": "Utiliser kJ au lieu de kcal",
@ -460,5 +459,8 @@
"Unpin": "Détacher",
"Split_All_Steps": "Diviser toutes les lignes en étapes séparées.",
"Warning_Delete_Supermarket_Category": "Supprimer une catégorie de supermarché supprimera également toutes les relations avec les aliments. Êtes-vous sûr ?",
"Instruction_Replace": "Instruction Remplacer"
"Instruction_Replace": "Instruction Remplacer",
"recipe_property_info": "Vous pouvez également ajouter des propriétés aux aliments pour les calculer automatiquement en fonction de votre recette !",
"per_serving": "par portions",
"open_data_help_text": "Le projet «Tandoor Open Data» est une base de données fournie par la communauté. Ce champ est rempli automatiquement lors de l'importation des données et permet les mises à jour dans le futur."
}

521
vue/src/locales/he.json Normal file
View File

@ -0,0 +1,521 @@
{
"warning_feature_beta": "יכולת זו כרגע בבטא. צפה שגיאות ואף תקלות בהמשך בעת שימוש ביכולת זו.",
"err_fetching_resource": "שגיאה בעת טעינת משאב!",
"err_creating_resource": "שגיאה בעת יצירת משאב!",
"err_updating_resource": "שגיאה בעת עדכון משאב!",
"err_deleting_resource": "שגיאה בעת מחיקת משאב!",
"err_deleting_protected_resource": "האובייקט שאתה מנסה למחור עדיין בשימוש ואי אפשר למחוקו.",
"err_moving_resource": "שגיאה בהעברת משאב!",
"err_merging_resource": "שגיאה בעת איחוד משאב!",
"success_fetching_resource": "משאב נטען בהצלחה!",
"success_creating_resource": "משאב נוצר בהצלחה!",
"success_updating_resource": "משאב עודן בהצלחה!",
"success_deleting_resource": "משאב נמחק בהצלחה!",
"success_moving_resource": "משאב הועבר בהצלחה!",
"success_merging_resource": "משאב אוחד בהצלחה!",
"file_upload_disabled": "העלאת קבצים לא מאופשרת במרחב זה.",
"recipe_property_info": "ניתן גם להוסיף ערכים למאכלים בכדי לחשב אוטומטית בהתאם למתכון שלך!",
"warning_space_delete": "ניתן למחיק את המרחב כולל כל המתכונים, רשימות קניות, תוכניות אוכל וכל מה שנוצר. פעולה זו הינה בלתי הפיכה! האם אתה בטוח ?",
"food_inherit_info": "ערכים על אוכל שאמורים להיות תורשתיים כברירת מחדל.",
"step_time_minutes": "זמן הצעד בדקות",
"confirm_delete": "האם אתה בטוח רוצה למחק את {object}?",
"import_running": "ייבוא מתבצע, נא להמתין!",
"all_fields_optional": "כל השדות הינן שדות רשות וניתן להשאירם ריקים.",
"convert_internal": "המר למתכון פנימי",
"show_only_internal": "הצג רק מתכונים פנימיים",
"show_split_screen": "תצוגה מפוצלת",
"Log_Recipe_Cooking": "רשום בישול מתכון",
"External_Recipe_Image": "תמונת מתכון חיצונית",
"Add_to_Shopping": "הוסף לקניות",
"Add_to_Plan": "הוסף לתוכנית",
"Step_start_time": "זמן התחלת הצעד",
"Sort_by_new": "סדר ע\"י חדש",
"Table_of_Contents": "תוכן עניינים",
"Recipes_per_page": "מתכונים בכל דף",
"Show_as_header": "הצג בתור כותרת",
"Hide_as_header": "הסתר בתור כותרת",
"Add_nutrition_recipe": "הוסף ערכים תזונתיים למתכון",
"Remove_nutrition_recipe": "מחר ערכים תזונתיים מהמתכון",
"Copy_template_reference": "העתק הפניה לתבנית",
"per_serving": "לפי מנה",
"Save_and_View": "שמור וצפה",
"Manage_Books": "נהל ספרים",
"Meal_Plan": "תוכנית ארוחה",
"Select_Book": "בחר ספר",
"Select_File": "בחר קובץ",
"Recipe_Image": "תמונת מתכון",
"Import_finished": "ייבוא הסתיים",
"View_Recipes": "הצג מתכונים",
"Log_Cooking": "רשום הכנת מתכון",
"New_Recipe": "מתכון חדש",
"Url_Import": "ייבוא מכתובת",
"Reset_Search": "אפס חיפוש",
"Recently_Viewed": "נצפו לאחרונה",
"Load_More": "טען עוד",
"New_Keyword": "מילת מפתח חדשה",
"Delete_Keyword": "מחר מילת מפתח",
"Edit_Keyword": "עדכן מילת מפתח",
"Edit_Recipe": "עדכן מתכון",
"Move_Keyword": "העברת מילת מפתח",
"Merge_Keyword": "איחוד מילת מפתח",
"Hide_Keywords": "הסתרת מילת מפתח",
"Hide_Recipes": "הסתרת מתכונים",
"Move_Up": "העברה למעלה",
"Move_Down": "העברה למטה",
"Step_Name": "שם צעד",
"Step_Type": "סוג צעד",
"Make_Header": "הפוך לכותרת",
"Make_Ingredient": "הפוך למרכיב",
"Amount": "כמות",
"Enable_Amount": "אפשר כמות",
"Disable_Amount": "אל תאפשר כמות",
"Ingredient Editor": "עורך המרכיבים",
"Description_Replace": "החלפת תיאור",
"Instruction_Replace": "החלפת הוראות",
"Auto_Sort": "סידור אוטומטי",
"Auto_Sort_Help": "העברת כל המרכיבים למיקום המתאים ביותר.",
"Private_Recipe": "מתכון פרטי",
"Private_Recipe_Help": "המתכון מוצג רק לך ולאנשים ששותפו.",
"reusable_help_text": "האם הכתובת השיתוף תהיה שמישה ליותר ממשתמש אחד.",
"open_data_help_text": "הקהילה מאחורי פרוייקט Tandoor Open Data תורמת מידע לTandoor. ערך זה ממולא אוטומטית כאשר מייברים אותו ומאפשר עדכון בעתיד.",
"Open_Data_Slug": "מידע פתוח",
"Open_Data_Import": "פתח ייבוא מידע",
"Data_Import_Info": "שפר את המרחב שלך ע\"י ייבוא רשימת משאבים קהילתית כמו מאכלים, ערכים ועוד.",
"Update_Existing_Data": "עדכון מידע קיים",
"Use_Metric": "השתמש ביחידות מטריות",
"Learn_More": "למד עוד",
"converted_unit": "יחידה מומרת",
"converted_amount": "כמות מומרת",
"base_unit": "יחידת בסיס",
"base_amount": "כמות בסיס",
"Datatype": "סוג מידע",
"Number of Objects": "מספר אובייקטים",
"Add_Step": "הוספת צעד",
"Keywords": "מילות מפתח",
"Books": "ספרים",
"Proteins": "פרוטאינים",
"Fats": "שומנים",
"Carbohydrates": "פחמימות",
"Calories": "קלוריות",
"Energy": "אנרגיה",
"Nutrition": "תזונה",
"Date": "תאריך",
"Share": "שיתוף",
"Automation": "אוטומטציה",
"Parameter": "פרמטר",
"Export": "ייצוא",
"Copy": "העתקה",
"Rating": "דירוג",
"Close": "סגירה",
"Cancel": "ביטול",
"Link": "קישור",
"Add": "הוספה",
"New": "חדש",
"Note": "הערה",
"Success": "הצלחה",
"Failure": "כשלון",
"Protected": "מוגן",
"Ingredients": "מרכיבים",
"Supermarket": "סופר מרקט",
"Categories": "קטגוריות",
"Category": "קטגוריה",
"Selected": "נבחר",
"min": "דקה",
"Servings": "מנות",
"Waiting": "המתנה",
"Preparation": "הכנה",
"External": "חיצוני",
"Size": "גודל",
"Files": "קבצים",
"File": "קובץ",
"Edit": "ערוך",
"Image": "תמונה",
"Delete": "מחק",
"Open": "פתח",
"Ok": "אישור",
"Save": "שמור",
"Step": "צעד",
"Search": "חיפוש",
"Import": "ייבוא",
"Print": "הדפסה",
"Settings": "הגדרות",
"or": "או",
"and": "וגם",
"Information": "מידע",
"Download": "הורדה",
"Create": "יצירה",
"Search Settings": "חיפוש הגדרות",
"View": "תצוגה",
"Recipes": "מתכונים",
"Welcome": "ברוכים הבאים",
"Move": "העברה",
"Merge": "איחוד",
"Parent": "הורה",
"Copy Link": "העתק קישור",
"Copy Token": "העתק טוקן",
"delete_confirmation": "האם אתה בטוח שאתה רוצה למחוק {source}?",
"move_confirmation": "העבר<i>{child}</i> אל הורה <i>{parent}</i>",
"merge_confirmation": "החלף <i>{source}</i> עם <i>{target}</i>",
"create_rule": "וגם צור אוטומציה",
"move_selection": "בחר הורה {type} להעביר את {source} אליו.",
"merge_selection": "החלף את כל העותקים של {source} בסוג הנבחר {type}.",
"Root": "ראשי",
"Ignore_Shopping": "התעלם מקניות",
"Shopping_Category": "קטגוריית קניות",
"Shopping_Categories": "קטגוריות קניות",
"Edit_Food": "ערוך אוכל",
"Move_Food": "העבר אוכל",
"New_Food": "אוכל חדש",
"Hide_Food": "הסתר אוכל",
"Food_Alias": "שם כינוי לאוכל",
"Unit_Alias": "שם כינוי ליחידה",
"Keyword_Alias": "שם כינוי למילת מפתח",
"Delete_Food": "מחק אוכל",
"No_ID": "מזהה לא נמצא, בלתי ניתן למחיקה.",
"Meal_Plan_Days": "תכנון אוכל עתידי",
"merge_title": "איחוד {type}",
"move_title": "העברה {type}",
"Food": "אוכל",
"Property": "נכס",
"Conversion": "עברית",
"Original_Text": "כיתוב מקורי",
"Recipe_Book": "ספר מתכון",
"del_confirmation_tree": "האם אתה בטוח שאתה רוצה למחק את {source] ואת כל ילדיו ?",
"delete_title": "מחק {type}",
"create_title": "חדש {type}",
"edit_title": "ערוך {type}",
"Name": "שם",
"Properties": "ערכים",
"Type": "סוג",
"Description": "תיאור",
"Recipe": "מתכון",
"tree_root": "מקור העץ",
"Icon": "צלמית",
"Unit": "ערך",
"Decimals": "דצימל",
"Default_Unit": "ערך ברירת מחדל",
"No_Results": "אין תוצאות",
"New_Unit": "יחידה חדשה",
"Create_New_Shopping Category": "צור קטגוריית קניות",
"Create_New_Food": "הוסף אוכל חדש",
"Create_New_Keyword": "הוסף מילת מפתח",
"Create_New_Unit": "הוסף יחידה",
"Create_New_Meal_Type": "הוסף סוג אוכל חדש",
"Create_New_Shopping_Category": "הוסף קטגוריות קניות חדשה",
"and_up": "ומעלה",
"and_down": "ומטה",
"Instructions": "הוראות",
"Unrated": "בלתי מדורג",
"Automate": "אוטומט",
"Empty": "ריק",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Time": "זמן",
"Text": "כתב",
"Shopping_list": "רשימת קניות",
"Added_by": "נוסף ע\"י",
"Added_on": "נוסף ב",
"AddToShopping": "הוסף לרשימת קניות",
"IngredientInShopping": "רכיב זה ברשימת הקניות.",
"NotInShopping": "{food} אינו רשימת הקניות.",
"OnHand": "כרגע נגיש",
"FoodOnHand": "יש {food} ברשותך.",
"FoodNotOnHand": "אין {food} ברשותך.",
"Undefined": "בלתי מוגדר",
"Create_Meal_Plan_Entry": "צור רשימת תכנון אוכל",
"Edit_Meal_Plan_Entry": "ערוך רשימת תכנון אוכל",
"Title": "כותרת",
"Week": "שבוע",
"Month": "חודש",
"Year": "שנה",
"Planner": "מתכנן",
"Planner_Settings": "הגדרות מתכנן",
"Period": "תקופה",
"Plan_Period_To_Show": "הצד שבועות, חודשים או שנים",
"Periods": "תקופות",
"Plan_Show_How_Many_Periods": "כמה תקופות להציג",
"Starting_Day": "יום תחילת השבוע",
"Meal_Types": "סוגי אוכל",
"Meal_Type": "סוג אוכל",
"New_Entry": "רשומה חדשה",
"Clone": "העתיק",
"Drag_Here_To_Delete": "משוך לכאן למחיקה",
"Meal_Type_Required": "סוג אוכל נדרש",
"Title_or_Recipe_Required": "בחירת כותרת או רכיב חובה",
"Color": "צבע",
"New_Meal_Type": "סוג אוכל חדש",
"Use_Fractions": "השתמש בשברים",
"Use_Fractions_Help": "המר אוטומטית מדצמילי לשברים כאשר צופים במתכון.",
"AddFoodToShopping": "",
"RemoveFoodFromShopping": "",
"DeleteShoppingConfirm": "",
"IgnoredFood": "",
"Add_Servings_to_Shopping": "",
"Week_Numbers": "",
"Show_Week_Numbers": "",
"Export_As_ICal": "",
"Export_To_ICal": "",
"Cannot_Add_Notes_To_Shopping": "",
"Added_To_Shopping_List": "",
"Shopping_List_Empty": "",
"Next_Period": "",
"Previous_Period": "",
"Current_Period": "",
"Next_Day": "",
"Previous_Day": "",
"Inherit": "",
"InheritFields": "",
"FoodInherit": "",
"ShowUncategorizedFood": "",
"GroupBy": "",
"Language": "",
"Theme": "",
"SupermarketCategoriesOnly": "",
"MoveCategory": "",
"CountMore": "...+{count} עוד",
"IgnoreThis": "לעולם אל תוסיף {food} לרשימת הקניות",
"DelayFor": "השהה ל {hours} שעות",
"Warning": "אזהרה",
"NoCategory": "לא נבחרה קטגוריה.",
"InheritWarning": "{food} מוגדר לרשת, שינויים עלולים להידרס.",
"ShowDelayed": "הצג פריטים מושהים",
"Completed": "הושלם",
"OfflineAlert": "אתה במצב מנותק, רשימת הקניות לא בהכרח מסונכרנת.",
"shopping_share": "שתף רשימת קניות",
"shopping_auto_sync": "סינכרון אוטומטי",
"one_url_per_line": "קישור בכל שורה",
"mealplan_autoadd_shopping": "הוסף תוכנית אוכל אוטומטית",
"mealplan_autoexclude_onhand": "אל תכלול מאכל נגיש",
"mealplan_autoinclude_related": "הוסף מתכון קשור",
"default_delay": "שעות השהייה ברירת מחדל",
"plan_share_desc": "רשומות תוכנית אוכל חדשות ישותפו אוטומטית עם המשתמשים שנבחרו.",
"shopping_share_desc": "משתמשים יראה את כל הפריטים ברשימת הקניות. הם חייבים להוסיף אותך בכדי שתוכל לראות את הרשימה שלהם.",
"shopping_auto_sync_desc": "הגדרת 0 יבטל את הסנכרון האוטומטי. כאשר צופים ברשימת קניות, הרשימת מתעדכנת בכל מספר שניות לשינויים שמישהו ייתכן ועשה. שימוש כאשר משתפים רשימה עם מספר אנשים שמשתמשים בחיבור נייד.",
"mealplan_autoadd_shopping_desc": "הוסף אוטומטית רכיבים מתוכנית האוכל לרשימת הקניות.",
"mealplan_autoexclude_onhand_desc": "כאשר מוסיפים רשימת אוכל לרשימת הקניות (ידנית או אוטומטית), אל תכלול מרכיבים נגישים.",
"mealplan_autoinclude_related_desc": "כאשר מוסיפים רשימת אוכל לרשימת הקניות (ידנית או אוטומטית), כלול את כל הרכיבים.",
"default_delay_desc": "ברירת מחדל של שעות שיהוי בהוספת פריט לרשימת קניות.",
"filter_to_supermarket": "סנן לסופרמרקט",
"Coming_Soon": "בקרוב",
"Auto_Planner": "מתכנן אוטומטי",
"New_Cookbook": "ספר מתכונים חדש",
"Hide_Keyword": "הסתר מילות מפתח",
"Hour": "שעה",
"Hours": "שעות",
"Day": "יום",
"Days": "ימים",
"Second": "שניה",
"Seconds": "שניות",
"Clear": "נקה",
"Users": "משתמשים",
"Invites": "הזמנות",
"err_move_self": "לא ניתן להעביר פריט לעצמו",
"nothing": "אין כלום מה לעשות",
"err_merge_self": "בלתי ניתן לאחד פריט עם עצמו",
"show_sql": "הצג SQL",
"filter_to_supermarket_desc": "בברירת המחדל, רשימת קניות כוללה רק את הקטגוריות לסופרמקט הנבחר.",
"CategoryName": "שם קטגוריה",
"SupermarketName": "שם סופרמרקט",
"CategoryInstruction": "",
"shopping_recent_days_desc": "",
"shopping_recent_days": "",
"download_pdf": "",
"download_csv": "",
"csv_delim_help": "",
"csv_delim_label": "",
"SuccessClipboard": "",
"copy_to_clipboard": "",
"csv_prefix_help": "תחילית להוספה כאשר מעתיקים את הרשימה ללוח הכתיבה.",
"csv_prefix_label": "רשימת תחיליות",
"copy_markdown_table": "העתק כטבלת Markdown",
"in_shopping": "ברשימת קניות",
"DelayUntil": "השהה עד",
"Pin": "נעץ",
"Unpin": "שחרר",
"PinnedConfirmation": "{recipe} ננעץ.",
"UnpinnedConfirmation": "{recipe} שוחרר מנעיצה.",
"mark_complete": "סמן כהסתיים",
"QuickEntry": "רשומה מהירה",
"shopping_add_onhand_desc": "סמן מאכל כנגיש לאחר שסומן ברשימת הקניות.",
"shopping_add_onhand": "נגיש ליד אוטומטי",
"related_recipes": "מתכונים קשורים",
"today_recipes": "מתכון היום",
"sql_debug": "תחקור SQL",
"remember_search": "זכור חיפוש",
"remember_hours": "זכור שעות",
"tree_select": "השתמש בבחירת עץ",
"OnHand_help": "מאכלים נמצאים במאגר ולא יתווספו אוטומטית לרשימת הקניות. מצב נגישות משותף בין משתמשי הרכישות.",
"ignore_shopping_help": "לעולם אל תוסיף מאכלים לרשימת הקניות (לדוגמא, מים)",
"shopping_category_help": "הזמנות מהסופרמרקט אפשריות וניתן לסננן על ידי קטגוריות רכישה בהתאם למעברים בחנות.",
"food_recipe_help": "קישור מתכון כאן יכלול את המתכון המקושר בכל מתכון אחר שמשתמש במאכל הזה",
"Foods": "מאכלים",
"Account": "חשבון",
"Cosmetic": "קוסמטי",
"API": "API",
"enable_expert": "אפשר מצב מתקדם",
"expert_mode": "מצב מתקדם",
"simple_mode": "מצב בסיסי",
"advanced": "מתקדם",
"fields": "שדות",
"show_keywords": "הצג מילות מפתח",
"show_foods": "הצג מאכלים",
"show_books": "הצג ספרים",
"show_rating": "הצג דירוג",
"show_units": "הצג יחידות",
"show_filters": "הצג סננים",
"not": "לא",
"save_filter": "שמור סנן",
"filter_name": "שם הסנן",
"left_handed": "מצב יד שמאל",
"left_handed_help": "יתאים את הממשק לשימוש ביד שמאל.",
"Custom Filter": "פילטר מותאם",
"shared_with": "שתף עם",
"sort_by": "סדר ע\"י",
"asc": "עולה",
"desc": "יורד",
"date_viewed": "נצפה לאחרונה",
"last_cooked": "בושל לאחרונה",
"times_cooked": "מספר הפעמים שבושל",
"date_created": "תאריך יציאה",
"show_sortby": "הצג סדר ע\"י",
"search_rank": "חיפוש דירוג",
"make_now": "עשה עכשיו",
"recipe_filter": "סנן מתכון",
"book_filter_help": "כלול מתכונים מתוך סנן המתכון בנוסף למתכונים שסומנו ידנית.",
"review_shopping": "עיין ברשימת הקניות לפני שמירה",
"view_recipe": "הצג מתכון",
"copy_to_new": "העתק למתכון חדש",
"recipe_name": "שם מתכון",
"paste_ingredients_placeholder": "הדבק רשימת רכיבים כאן...",
"paste_ingredients": "הדבק מרכיבים",
"ingredient_list": "רשימת רכיבים",
"explain": "הסבר",
"filter": "סנן",
"Website": "אתר",
"App": "אפליקציה",
"Message": "הודעה",
"Bookmarklet": "סימניה",
"Sticky_Nav": "ניווט דביק",
"Sticky_Nav_Help": "תמיד הצג את תפריט הניווט בראש העמוד.",
"Nav_Color": "צבע ניווט",
"Nav_Color_Help": "שנה את צבע הניווט.",
"Use_Kj": "השתמש בקילוג'אול במקום קילוקלוריות",
"Comments_setting": "הצג תגובות",
"click_image_import": "בחר תמונה שתרצה לייבוא למתכון זה",
"no_more_images_found": "לא נמצאו תמונות נוספות באתר.",
"import_duplicates": "למנוע מצב של מתכונים כפולים עם אותו השם. סמן כאן לייבא הכל.",
"paste_json": "הדבק JSON או HTML כאן לטעינת מתכון.",
"Click_To_Edit": "לחץ לעריכה",
"search_no_recipes": "לא נמצאו כל מתכונים!",
"search_import_help_text": "ייבא מתכון מאתר חיצוני או אפליקציה.",
"search_create_help_text": "צור מתכון חדש ישירות בTandoor.",
"warning_duplicate_filter": "אזהרה: בשל אתגרים טכנולוגיים, השימוש במספר מסננים בעל אותו צירוף עלול לגרום לתוצאות בלתי צפויות.",
"reset_children": "אפס ירושה מילדים",
"reset_children_help": "דרוס את כל ערכי הילדים עם ערכים תורשתיים. ערכים תורשתיים יוגדרו ערכים נורשים אלא אם הערך כבר קיים.",
"reset_food_inheritance": "אפס הורשה",
"reset_food_inheritance_info": "",
"substitute_help": "תחליפים נלקחים בחשבון כאשר מחשפים מתכונים שאפשר להכין עם מרכיבים נגישים.",
"substitute_siblings_help": "כל המאכלים שחולקים הורה, נחשבים תחליפים.",
"substitute_children_help": "כל המאכלים אשר מוגדרים כילדים של המאכל הזה, נחשבים תחליפים.",
"substitute_siblings": "החלפת דומים",
"substitute_children": "החלפת ילדים",
"SubstituteOnHand": "",
"ChildInheritFields": "",
"ChildInheritFields_help": "",
"InheritFields_help": "",
"show_ingredient_overview": "",
"Ingredient Overview": "",
"last_viewed": "נצפה לאחרונה",
"created_on": "נוצר ב",
"updatedon": "עודכן ב",
"Imported_From": "יובא מ",
"advanced_search_settings": "הגדרות חיפוש מתקדמות",
"nothing_planned_today": "שום דבר מתכונן היום!",
"no_pinned_recipes": "אין מתכונים נעוצים!",
"Planned": "מתוכנן",
"Pinned": "נעוץ",
"Imported": "מיובא",
"Quick actions": "פעולות מהירות",
"Ratings": "דירוג",
"Internal": "פנימי",
"Units": "יחידות",
"Manage_Emails": "נהל כתובות דואר אלקטרוני",
"Change_Password": "החלפת סיסמא",
"Social_Authentication": "",
"Random Recipes": "",
"parameter_count": "פרטמר {count}",
"select_keyword": "",
"add_keyword": "",
"select_file": "",
"select_recipe": "",
"select_unit": "",
"select_food": "בחר מאכל",
"remove_selection": "הסר בחירה",
"empty_list": "הרשימה ריקה.",
"Select": "בחר",
"Supermarkets": "סופרמרקטים",
"User": "משתמש",
"Username": "שם משתמש",
"First_name": "שם פרטי",
"Last_name": "שם משפחה",
"Keyword": "מילת מפתח",
"Advanced": "מתקדם",
"Page": "עמוד",
"Single": "בודד",
"Multiple": "מרובה",
"Reset": "אפס",
"Disabled": "מושבת",
"Disable": "השבת",
"Options": "אפשרויות",
"Create Food": "צור מאכל",
"create_food_desc": "צור מאכל וקשרו למתכון.",
"additional_options": "אפשרויות נוספות",
"Importer_Help": "עוד מידע ועזרה על כלי ייבוא זה:",
"Documentation": "תיעוד",
"Select_App_To_Import": "בחור אפליקציה לייבוא מתוך",
"Import_Supported": "ייבוא נתמך",
"Export_Supported": "ייצוא נתמך",
"Import_Not_Yet_Supported": "ייבוא לא נתמך עדיין",
"Export_Not_Yet_Supported": "ייצוא לא נתמך עדיין",
"Import_Result_Info": "{imported} מתוך {total} מתכונים יובאו",
"Recipes_In_Import": "מתכון בקובץ הייבוא",
"Toggle": "אפשר",
"total": "סך הכל",
"Import_Error": "שגיאה בעת ייבוא. הרחב את הפירוט בסוף עמוד זה לראות מידע נוסף.",
"Warning_Delete_Supermarket_Category": "מחיקת קטגורית סופרמרקט תמחוק גם את המאכלים הקשורים. האם אתה בטוח ?",
"New_Supermarket": "צור סופרמרקט חדש",
"New_Supermarket_Category": "צור קטגורית סופרמקט חדשה",
"Are_You_Sure": "בטוח?",
"Valid Until": "פעיל עד",
"Split_All_Steps": "פצל את כל השורות לצעדים נפרדים.",
"Combine_All_Steps": "אחד את כל הצעדים לשדה אחד.",
"Plural": "רבים",
"plural_short": "רבים",
"g": "גרם (g)",
"kg": "קילוגרם [kg]",
"ounce": "אונקיה [oz]",
"pound": "פאונד (משקל)",
"ml": "מיליליטר [ml]",
"l": "ליטר [l]",
"fluid_ounce": "אונקיה נוזלית [fl oz]",
"pint": "פיינט [pt]",
"quart": "קווארט [qt]",
"gallon": "גלון [gal]",
"tbsp": "כף",
"tsp": "כפית",
"imperial_fluid_ounce": "אונקיה אמפיריאלית",
"imperial_pint": "פינט אימפריאלי",
"imperial_quart": "קווארט אימפריאלי",
"imperial_gallon": "גאלון אימפריאלי",
"imperial_tbsp": "כף אימפריאלית",
"imperial_tsp": "כפית אימפריאלית",
"Choose_Category": "בחר קטגוריה",
"Back": "חזור",
"Use_Plural_Unit_Always": "תמיד השתמש ברבים ליחידות",
"Use_Plural_Unit_Simple": "השתמש ברבים ליחידות בצורה דינאמית",
"Use_Plural_Food_Always": "תמיד השתמש בצורת רבים למאכלים",
"Use_Plural_Food_Simple": "השתמש בצורת רבים למאכלים בצורה דינאמית",
"plural_usage_info": "תמיד השתמש בצורת רבים למאכלים במרחב זה.",
"Create Recipe": "צור מתכון",
"Import Recipe": "ייבא מתכון"
}

View File

@ -16,7 +16,6 @@
"file_upload_disabled": "Unggahan file tidak diaktifkan untuk ruang Anda.",
"warning_space_delete": "Anda dapat menghapus ruang Anda termasuk semua resep, daftar belanja, rencana makan, dan apa pun yang telah Anda buat. Ini tidak dapat dibatalkan! Apakah Anda yakin ingin melakukan ini?",
"food_inherit_info": "Bidang pada makanan yang harus diwarisi secara default.",
"facet_count_info": "Tampilkan jumlah resep pada filter pencarian.",
"step_time_minutes": "Langkah waktu dalam menit",
"confirm_delete": "Anda yakin ingin menghapus {object} ini?",
"import_running": "Impor berjalan, harap tunggu!",

View File

@ -304,7 +304,6 @@
"tree_select": "Usa selezione ad albero",
"sql_debug": "Debug SQL",
"remember_search": "Ricorda ricerca",
"facet_count_info": "Mostra il conteggio delle ricette nei filtri di ricerca.",
"warning_space_delete": "Stai per eliminare la tua istanza che include tutte le ricette, liste della spesa, piani alimentari e tutto ciò che hai creato. Questa azione non può essere annullata! Sei sicuro di voler procedere?",
"food_inherit_info": "Campi di alimenti che devono essere ereditati per impostazione predefinita.",
"enable_expert": "Abilita modalità esperto",
@ -466,5 +465,10 @@
"Original_Text": "Testo originale",
"search_rank": "Posizione di ricerca",
"make_now": "Fai ora",
"Amount": "Quantità"
"Amount": "Quantità",
"show_step_ingredients_setting": "Mostra gli ingredienti vicino ai passaggi della ricetta",
"substitute_siblings_help": "Tutti gli alimenti che condividono un genitore di questo alimento sono considerati sostituti",
"reset_children": "Reimposta l'eredità degli eredi",
"substitute_siblings": "Sostituire prodotti eredi",
"ChildInheritFields": "Gli eredi ereditano i valori"
}

500
vue/src/locales/nb_NO.json Normal file
View File

@ -0,0 +1,500 @@
{
"warning_feature_beta": "Denne funksjonen er foreløpig i BETA-versjon (testing). Regn med feil og at det i fremtidige oppdateringer kan komme endringer som gjør funksjonen ubrukelig.",
"err_fetching_resource": "Feil ved henting av ressurs!",
"err_creating_resource": "Feil ved oppretting av ressurs!",
"err_updating_resource": "Feil ved oppdatering av ressurs!",
"err_deleting_resource": "Feil ved sletting av ressurs!",
"err_deleting_protected_resource": "Objektet du prøver å slette er fortsatt i bruk, og kan ikke slettes.",
"err_moving_resource": "Feil ved flytting av ressurs!",
"err_merging_resource": "Feil ved sammenslåing av ressurs!",
"success_fetching_resource": "Vellykket henting av ressurs!",
"success_creating_resource": "Vellykket oppretting av ressurs!",
"success_updating_resource": "Vellykket oppdatering av ressurs!",
"success_deleting_resource": "Vellykket sletting av ressurs!",
"success_moving_resource": "Vellykket flytting av ressurs!",
"success_merging_resource": "Vellykket sammenslåing av ressurs!",
"file_upload_disabled": "Opplasting av filer er ikke aktivert i området ditt.",
"warning_space_delete": "Du kan slette området, inkludert alle oppskrifter, handlelister, måltidsplaner og alt annet du har opprettet. Dette kan ikke angres! Er du sikker på at du vil gjøre dette?",
"food_inherit_info": "Felter på matvarer som skal arves som standard.",
"step_time_minutes": "Tid for trinn, i minutter",
"confirm_delete": "Er du sikker på at du vil slette dette {object}?",
"import_running": "Importering pågår. Vennligst vent!",
"all_fields_optional": "Alle felt er valgfri, og kan stå tomme.",
"convert_internal": "Konverter til intern oppskrift",
"show_only_internal": "Vis bare interne oppskrifter",
"show_split_screen": "Delt visning",
"Log_Recipe_Cooking": "Logg oppskriftsbruk",
"External_Recipe_Image": "Bilde av ekstern oppskrift",
"Add_to_Shopping": "Legg til i handleliste",
"Add_to_Plan": "Legg til i Plan",
"Step_start_time": "Trinn starttid",
"Sort_by_new": "Sorter etter nyest",
"Table_of_Contents": "Innholdsfortegnelse",
"Recipes_per_page": "Oppskrifter per side",
"Show_as_header": "Vis som overskrift",
"Hide_as_header": "Skjul overskrift",
"Add_nutrition_recipe": "Legg til næringsinnhold til oppskrift",
"Remove_nutrition_recipe": "Fjern næringsinnhold fra oppskrift",
"Copy_template_reference": "Kopier mal-referanse",
"Save_and_View": "Lagre og vis",
"Manage_Books": "Administrer bøker",
"Meal_Plan": "Måltidsplan",
"Select_Book": "Velg bok",
"Select_File": "Velg fil",
"Recipe_Image": "Oppskriftsbilde",
"Import_finished": "Importering fullført",
"View_Recipes": "Vis oppskrifter",
"Log_Cooking": "Loggfør tilbereding",
"New_Recipe": "Ny oppskrift",
"Url_Import": "Importer lenke",
"Reset_Search": "Nullstill søk",
"Recently_Viewed": "Nylig vist",
"Load_More": "Last inn flere",
"New_Keyword": "Nytt nøkkelord",
"Delete_Keyword": "Slett nøkkelord",
"Edit_Keyword": "Rediger nøkkelord",
"Edit_Recipe": "Rediger oppskrift",
"Move_Keyword": "Flytt nøkkelord",
"Merge_Keyword": "Slå sammen nøkkelord",
"Hide_Keywords": "Skjul nøkkelord",
"Hide_Recipes": "Skjul oppskrifter",
"Move_Up": "Flytt opp",
"Move_Down": "Flytt ned",
"Step_Name": "Trinn navn",
"Step_Type": "Trinn type",
"Make_Header": "Bruk som overskrift",
"Make_Ingredient": "Bruk som ingrediens",
"Amount": "Mengde",
"Enable_Amount": "Aktiver mengde",
"Disable_Amount": "Deaktiver mengde",
"Ingredient Editor": "Ingrediens Behandler",
"Description_Replace": "Erstatt beskrivelse",
"Instruction_Replace": "Erstatt instruksjoner",
"Auto_Sort": "Sorter Automatisk",
"Auto_Sort_Help": "Flytt alle ingredienser til det mest passende steget.",
"Private_Recipe": "Privat Oppskrift",
"Private_Recipe_Help": "Oppskriften er bare vist til deg og dem du har delt den med.",
"reusable_help_text": "Burde invitasjonslenken være brukbar for flere enn én bruker.",
"Add_Step": "Legg til steg",
"Keywords": "Nøkkelord",
"Books": "Bøker",
"Proteins": "Protein",
"Fats": "Fett",
"Carbohydrates": "Karbohydrater",
"Calories": "Kalorier",
"Energy": "Energi",
"Nutrition": "Næring",
"Date": "Dato",
"Share": "Del",
"Automation": "Automatiser",
"Parameter": "Parameter",
"Export": "Eksporter",
"Copy": "Kopier",
"Rating": "Vurdering",
"Close": "Lukk",
"Cancel": "Avbryt",
"Link": "Lenke",
"Add": "Legg til",
"New": "Ny",
"Note": "Merk",
"Success": "Vellykket",
"Failure": "Feil",
"Protected": "Beskyttet",
"Ingredients": "Ingredienser",
"Supermarket": "Butikk",
"Categories": "Kategorier",
"Category": "Kategori",
"Selected": "Valgte",
"min": "min",
"Servings": "Porsjoner",
"Waiting": "Venter",
"Preparation": "Forberedelse",
"External": "Ekstern",
"Size": "Størrelse",
"Files": "Filer",
"File": "Fil",
"Edit": "Rediger",
"Image": "Bilde",
"Delete": "Slett",
"Open": "Åpne",
"Ok": "Ok",
"Save": "Lagre",
"Step": "Steg",
"Search": "Søk",
"Import": "Importer",
"Print": "Skriv ut",
"Settings": "Innstillinger",
"or": "eller",
"and": "og",
"Information": "Informasjon",
"Download": "Last ned",
"Create": "Opprett",
"Search Settings": "Søk Instillinger",
"View": "Visning",
"Recipes": "Oppskrift",
"Move": "Flytt",
"Merge": "Slå sammen",
"Parent": "Forelder",
"Copy Link": "Kopier lenke",
"Copy Token": "Kopier Token",
"delete_confirmation": "Er du sikker på at du vill slette {source}?",
"move_confirmation": "Flytt<i>{child}</i> til forelder <i>{parent}</i>",
"merge_confirmation": "Erstatt<i>{source}</i> med <i>{target}</i>",
"create_rule": "og opprett automasjon",
"move_selection": "Velg en forelder {type} å flytte {source} til.",
"merge_selection": "Erstatt alle tilfeller av {source} med den valgte {type}.",
"Root": "Rot",
"Ignore_Shopping": "Ignorer Handlekurv",
"Shopping_Category": "Butikk Kategori",
"Shopping_Categories": "Butikk Kategorier",
"Edit_Food": "Rediger Matrett",
"Move_Food": "Flytt Matrett",
"New_Food": "Ny Matrett",
"Hide_Food": "Skjul Matrett",
"Food_Alias": "Matrett Alias",
"Unit_Alias": "Enhet Alias",
"Keyword_Alias": "Nøkkelord Alias",
"Delete_Food": "Slett Matrett",
"No_ID": "ID ikke funnet, kan ikke slette.",
"Meal_Plan_Days": "Fremtidige måltidsplaner",
"merge_title": "Slå sammen {type}",
"move_title": "Flytt {type}",
"Food": "Matretter",
"Original_Text": "Orginal tekst",
"Recipe_Book": "Oppskriftsbok",
"del_confirmation_tree": "Er du sikker på at du vil slette {source} og alt under?",
"delete_title": "Slett {type}",
"create_title": "Ny {type}",
"edit_title": "Rediger {type}",
"Name": "Navn",
"Type": "Type",
"Description": "Beskrivelse",
"Recipe": "Oppskrift",
"tree_root": "Rot av tre",
"Icon": "Ikon",
"Unit": "Enhet",
"Decimals": "Desimaler",
"Default_Unit": "Standard Enhet",
"No_Results": "Ingen resultat",
"New_Unit": "Ny Enhet",
"Create_New_Shopping Category": "Opprett ny handle kategori",
"Create_New_Food": "Opprett ny matrett",
"Create_New_Keyword": "Opprett nytt nøkkelord",
"Create_New_Unit": "Opprett ny enhet",
"Create_New_Meal_Type": "Opprett ny matrett type",
"Create_New_Shopping_Category": "Opprett new handle kategori",
"and_up": "& Opp",
"and_down": "& Ned",
"Instructions": "Instruksjoner",
"Unrated": "Urangert",
"Automate": "Automatiser",
"Empty": "Tom",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Time": "Tid",
"Text": "Tekst",
"Shopping_list": "Handleliste",
"Added_by": "Lagt til av",
"Added_on": "Lagt til",
"AddToShopping": "Legg til i handleliste",
"IngredientInShopping": "Denne ingrediensen er i handlekurven din.",
"NotInShopping": "{food} er ikke i handlelisten din.",
"OnHand": "På lager",
"FoodOnHand": "Du har {food} på lager.",
"FoodNotOnHand": "Du har ikke {food} på lager.",
"Undefined": "Udefinert",
"Create_Meal_Plan_Entry": "Opprett måltidsplanoppføring",
"Edit_Meal_Plan_Entry": "Rediger måltidsplanoppføring",
"Title": "Tittel",
"Week": "Uke",
"Month": "Måned",
"Year": "År",
"Planner": "Planlegger",
"Planner_Settings": "Planleggingsinstilliger",
"Period": "Periode",
"Plan_Period_To_Show": "Vis uke, måned eller år",
"Periods": "Perioder",
"Plan_Show_How_Many_Periods": "Hvor mange perioder skal vises",
"Starting_Day": "Dag uken skal state på",
"Meal_Types": "Måltidstyper",
"Meal_Type": "Måltidstype",
"New_Entry": "Ny oppføring",
"Clone": "Klon",
"Drag_Here_To_Delete": "Dra her for å slette",
"Meal_Type_Required": "Måltidstype er nødvendig",
"Title_or_Recipe_Required": "Tittel- eller oppskrifts-valg nødvendig",
"Color": "Farge",
"New_Meal_Type": "Ny Måltidstype",
"Use_Fractions": "Bruk deler",
"Use_Fractions_Help": "Automatisk konverter desimaler til deler når du ser på en oppskrift.",
"AddFoodToShopping": "Legg til {food] i handlelisten din",
"RemoveFoodFromShopping": "Fjern {food} fra handelisten din",
"DeleteShoppingConfirm": "Er du sikker på at du fjerne alle {food} fra handlelisten?",
"IgnoredFood": "",
"Add_Servings_to_Shopping": "Legg til {servings} serveringer i handlelisten",
"Week_Numbers": "Ukenummer",
"Show_Week_Numbers": "Vis ukenummer?",
"Export_As_ICal": "Eksporter gjeldende periode som iCal format",
"Export_To_ICal": "Eksporter .ics",
"Cannot_Add_Notes_To_Shopping": "Notater kan ikke legges til i handlelisten",
"Added_To_Shopping_List": "Lagt til i handlelisten",
"Shopping_List_Empty": "",
"Next_Period": "Neste periode",
"Previous_Period": "Forrige periode",
"Current_Period": "Gjeldende periode",
"Next_Day": "Neste dag",
"Previous_Day": "Forrige dag",
"Inherit": "Arve",
"InheritFields": "Arv feltverdier",
"FoodInherit": "Arvbare felt for matvarer",
"ShowUncategorizedFood": "Vis udefinerte",
"GroupBy": "Grupér",
"Language": "Språk",
"Theme": "Tema",
"SupermarketCategoriesOnly": "Kun Butikkategorier",
"MoveCategory": "Flytt til: ",
"CountMore": "...+{count} til",
"IgnoreThis": "Aldri legg til {food} automatisk i handlelisten",
"DelayFor": "Utsett i {hours} timer",
"Warning": "Advarsel",
"NoCategory": "Ingen kategori valgt.",
"InheritWarning": "",
"ShowDelayed": "Vis Utsatte Gjenstander",
"Completed": "Fullført",
"OfflineAlert": "Du er ikke koblet til internett. Det kan hende handlelisten ikke synkroniserer.",
"shopping_share": "Del handlelisten",
"shopping_auto_sync": "Synkroniser automatisk",
"one_url_per_line": "En Lenke per linje",
"mealplan_autoadd_shopping": "Automatisk legg til måltidsplan",
"mealplan_autoexclude_onhand": "Eksluder mat på lager",
"mealplan_autoinclude_related": "Legg til relaterte oppskrifter",
"default_delay": "Standard Timer å Utsette",
"plan_share_desc": "Nye måltidsplaner vil automatisk bli delt med valgte brukere.",
"shopping_share_desc": "Brukere vil se alle gjenstander du har lagt til i handlelisten. Brukerne må legge deg til for at du kan se deres gjenstander på handlelisten.",
"shopping_auto_sync_desc": "",
"mealplan_autoadd_shopping_desc": "",
"mealplan_autoexclude_onhand_desc": "",
"mealplan_autoinclude_related_desc": "",
"default_delay_desc": "",
"filter_to_supermarket": "",
"Coming_Soon": "Kommer snart",
"Auto_Planner": "",
"New_Cookbook": "Ny kokebok",
"Hide_Keyword": "Skjul nøkkelord",
"Hour": "Time",
"Hours": "Timer",
"Day": "Dag",
"Days": "Dager",
"Second": "Sekund",
"Seconds": "Sekunder",
"Clear": "Fjern",
"Users": "Brukere",
"Invites": "Invitasjoner",
"err_move_self": "Kan ikke flytte elementet til seg selv",
"nothing": "Ingenting å gjøre",
"err_merge_self": "Kan ikke slå sammen linje med seg selv",
"show_sql": "Vis SQL",
"filter_to_supermarket_desc": "Som standard, filtrerer handlelisten til å kun inkludere kategorier for den valgte butikken.",
"CategoryName": "Kategori navn",
"SupermarketName": "Butikk Navn",
"CategoryInstruction": "Dra kategorier for å endre på rekkefølgen de vises i handlelisten.",
"shopping_recent_days_desc": "",
"shopping_recent_days": "De siste dagene",
"download_pdf": "Last ned PDF",
"download_csv": "Last ned CSV",
"csv_delim_help": "Skilletegn som skal brukes for CSV-eksport.",
"csv_delim_label": "CSV-skilletegn",
"SuccessClipboard": "Handleliste kopiert til utklippstavlen",
"copy_to_clipboard": "Kopier til utklippstavle",
"csv_prefix_help": "Prefiks for å legge til når du kopierer listen til utklippstavlen.",
"csv_prefix_label": "Liste prefiks",
"copy_markdown_table": "Kopier som Markdown tabell",
"in_shopping": "I handleliste",
"DelayUntil": "Forsink til",
"Pin": "Fest",
"Unpin": "Løsne",
"PinnedConfirmation": "{recipe} har blitt festet.",
"UnpinnedConfirmation": "{recipe} har blitt løsnet.",
"mark_complete": "Marker som fullført",
"QuickEntry": "Hurtigregistrering",
"shopping_add_onhand_desc": "",
"shopping_add_onhand": "",
"related_recipes": "",
"today_recipes": "",
"sql_debug": "",
"remember_search": "",
"remember_hours": "",
"tree_select": "",
"OnHand_help": "",
"ignore_shopping_help": "",
"shopping_category_help": "",
"food_recipe_help": "",
"Foods": "",
"Account": "",
"Cosmetic": "Kosmetisk",
"API": "API",
"enable_expert": "Aktiver Ekspert Modus",
"expert_mode": "Ekspert Modus",
"simple_mode": "Enkel Modus",
"advanced": "Avansert",
"fields": "Felt",
"show_keywords": "Vis Nøkkelord",
"show_foods": "Vis Mat",
"show_books": "Vis bøker",
"show_rating": "Vis vurdering",
"show_units": "Vis enheter",
"show_filters": "Vis filtre",
"not": "ikke",
"save_filter": "Lagre filtre",
"filter_name": "Filtrer Navn",
"left_handed": "Venstrehendt Modus",
"left_handed_help": "Vil optimalisere bukergrensesnittet for bruk med venstre hånden.",
"Custom Filter": "Egendefinert Filter",
"shared_with": "Delt med",
"sort_by": "Sorter etter",
"asc": "Stigende",
"desc": "Fallende",
"date_viewed": "Sist sett",
"last_cooked": "Sist tilberedt",
"times_cooked": "Antall ganger tilberedt",
"date_created": "Dato laget",
"show_sortby": "Vis sorter etter",
"search_rank": "Søk etter vurdering",
"make_now": "Lag nå",
"recipe_filter": "Oppskrift filter",
"book_filter_help": "",
"review_shopping": "",
"view_recipe": "",
"copy_to_new": "",
"recipe_name": "",
"paste_ingredients_placeholder": "",
"paste_ingredients": "",
"ingredient_list": "",
"explain": "",
"filter": "",
"Website": "Nettside",
"App": "App",
"Message": "Melding",
"Bookmarklet": "",
"Sticky_Nav": "",
"Sticky_Nav_Help": "",
"Nav_Color": "",
"Nav_Color_Help": "",
"Use_Kj": "",
"Comments_setting": "",
"click_image_import": "",
"no_more_images_found": "",
"import_duplicates": "",
"paste_json": "",
"Click_To_Edit": "",
"search_no_recipes": "",
"search_import_help_text": "",
"search_create_help_text": "",
"warning_duplicate_filter": "",
"reset_children": "",
"reset_children_help": "",
"reset_food_inheritance": "",
"reset_food_inheritance_info": "",
"substitute_help": "",
"substitute_siblings_help": "",
"substitute_children_help": "",
"substitute_siblings": "",
"substitute_children": "",
"SubstituteOnHand": "",
"ChildInheritFields": "",
"ChildInheritFields_help": "",
"InheritFields_help": "",
"show_ingredient_overview": "",
"Ingredient Overview": "",
"last_viewed": "",
"created_on": "",
"updatedon": "",
"Imported_From": "",
"advanced_search_settings": "",
"nothing_planned_today": "",
"no_pinned_recipes": "",
"Planned": "",
"Pinned": "",
"Imported": "",
"Quick actions": "",
"Ratings": "",
"Internal": "",
"Units": "Enhet",
"Manage_Emails": "Administrer e-poster",
"Change_Password": "Endre passord",
"Social_Authentication": "",
"Random Recipes": "Tilfeldige oppskrifter",
"parameter_count": "",
"select_keyword": "",
"add_keyword": "",
"select_file": "",
"select_recipe": "",
"select_unit": "",
"select_food": "",
"remove_selection": "",
"empty_list": "",
"Select": "Velg",
"Supermarkets": "Butikker",
"User": "Bruker",
"Username": "Brukernavn",
"First_name": "Fornavn",
"Last_name": "Etternavn",
"Keyword": "Nøkkelord",
"Advanced": "Avansert",
"Page": "",
"Single": "",
"Multiple": "",
"Reset": "",
"Disabled": "",
"Disable": "",
"Options": "",
"Create Food": "",
"create_food_desc": "",
"additional_options": "",
"Importer_Help": "",
"Documentation": "",
"Select_App_To_Import": "",
"Import_Supported": "",
"Export_Supported": "",
"Import_Not_Yet_Supported": "",
"Export_Not_Yet_Supported": "",
"Import_Result_Info": "",
"Recipes_In_Import": "",
"Toggle": "",
"Import_Error": "",
"Warning_Delete_Supermarket_Category": "",
"New_Supermarket": "",
"New_Supermarket_Category": "",
"Are_You_Sure": "",
"Valid Until": "",
"Split_All_Steps": "",
"Combine_All_Steps": "",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": "",
"Create Recipe": "",
"Import Recipe": "Importer oppskrift",
"per_serving": "Per porsjon",
"open_data_help_text": "Tandoor Open Data prosjektet gir fra fellesskapet til Tandoor. Dette feltet fylles ut automatisk når det importeres og tillater oppdateringer i fremtiden.",
"Open_Data_Slug": "Åpne data Slug",
"Open_Data_Import": "Åpne Data Import",
"recipe_property_info": "Du kan også legge til egenskaper til mat for å kalkulere dem automatisk basert på oppskriften!",
"Update_Existing_Data": "Oppdater eksisterende data",
"Use_Metric": "Bruk metriske enheter",
"Learn_More": "Lær mer",
"converted_unit": "Konverter enhet",
"converted_amount": "Konverter mengde",
"base_unit": "Baseenhet",
"base_amount": "Basemengde",
"Datatype": "Data-type",
"Number of Objects": "Antall objekter",
"Property": "Egenskap",
"Conversion": "Omregn enhet",
"Properties": "Egenskaper",
"Alignment": "Justering",
"Welcome": "Velkommen"
}

View File

@ -464,8 +464,7 @@
"Valid Until": "Geldig tot",
"warning_space_delete": "Je kunt jouw space verwijderen inclusief alle recepten, boodschappenlijstjes, maaltijdplannen en alles wat je verder aangemaakt hebt. Dit kan niet ongedaan worden gemaakt! Weet je het zeker?",
"food_inherit_info": "Voedselvelden die standaard geërfd worden.",
"facet_count_info": "Geef receptenaantal bij zoekfilters weer.",
"Split_All_Steps": "Splits alle rijen in apparte stappen.",
"Split_All_Steps": "Splits alle rijen in aparte stappen.",
"Combine_All_Steps": "Voeg alle stappen samen tot een veld.",
"Plural": "Meervoud",
"plural_short": "meervoud",
@ -480,5 +479,46 @@
"Description_Replace": "Vervang beschrijving",
"Instruction_Replace": "Vervang instructie",
"Auto_Sort_Help": "Verplaats alle ingrediënten naar de best passende stap.",
"Auto_Sort": "Automatisch sorteren"
"Auto_Sort": "Automatisch sorteren",
"Create Recipe": "Recept Maken",
"Import Recipe": "Recept Importeren",
"recipe_property_info": "Je kunt ook eigenschappen aan voedingsmiddelen toevoegen om ze automatisch te berekenen op basis van je recept!",
"per_serving": "per portie",
"Open_Data_Slug": "Open Data Slug",
"Open_Data_Import": "Open Data Import",
"Update_Existing_Data": "Bestaande gegevens bijwerken",
"Use_Metric": "Metrische eenheden gebruiken",
"Learn_More": "Meer informatie",
"converted_unit": "Aangepaste eenheid",
"converted_amount": "Aangepast Bedrag",
"Datatype": "Datatype",
"Number of Objects": "Aantal Objecten",
"open_data_help_text": "Het Tandoor Open Data-project biedt door de community bijgedragen gegevens voor Tandoor. Dit veld wordt automatisch gevuld bij het importeren en maakt updates in de toekomst mogelijk.",
"Data_Import_Info": "Verbeter je Space door een door de community samengestelde lijst van voedingsmiddelen, eenheden en meer te importeren om je receptenverzameling te verbeteren.",
"base_unit": "Basis Unit",
"base_amount": "Basisbedrag",
"Welcome": "Welkom",
"quart": "quart [qt] (VS, volume)",
"imperial_fluid_ounce": "imperial fluid ounce [imp fl oz] (Verenigd Koninkrijk, volume)",
"imperial_tbsp": "imperial theelepel [imp tbsp] (Verenigd Koningrijk, volume)",
"Property": "Eigenschap",
"Conversion": "Omrekening",
"Properties": "Eigenschappen",
"total": "totaal",
"g": "gram [g] (metrisch, gewicht)",
"kg": "kilogram [kg] (metrisch, gewicht)",
"ounce": "ons [oz] (gewicht)",
"pound": "pond (gewicht)",
"ml": "milliliter [ml] (metrisch, volume)",
"l": "liter [l] (metrisch, volume)",
"pint": "pint [pt] (VS, volume)",
"gallon": "gallon [gal] (VS, volume)",
"tbsp": "tablespoon [tbsp] (VS, volume)",
"tsp": "theelepel [tsp] (VS, volume)",
"imperial_pint": "imperial pint [imp pt] (Verenigd Koninkrijk, volume)",
"imperial_quart": "imperial quart [imp qt] (Verenigd Koninkrijk, volume)",
"imperial_gallon": "imperial gal [imp gal] (Verenigd Koninkrijk, volume)",
"imperial_tsp": "imperial thelepel [imp tsp] (UK, volume)",
"Choose_Category": "Kies Categorie",
"Back": "Terug"
}

View File

@ -420,7 +420,6 @@
"Users": "Użytkownicy",
"Invites": "Zaprasza",
"food_inherit_info": "Pola w pożywieniu, które powinny być domyślnie dziedziczone.",
"facet_count_info": "Pokaż ilości przepisów w filtrach wyszukiwania.",
"Copy Token": "Kopiuj Token",
"Message": "Wiadomość",
"reset_food_inheritance": "Zresetuj dziedziczenie",
@ -480,5 +479,59 @@
"Description_Replace": "Zmień opis",
"Instruction_Replace": "Zmień instrukcję",
"Import Recipe": "Importuj przepis",
"Create Recipe": "Utwórz przepis"
"Create Recipe": "Utwórz przepis",
"recipe_property_info": "Możesz także dodawać właściwości do żywności, aby przeliczać ją automatycznie na podstawie Twojego przepisu!",
"per_serving": "na porcje",
"open_data_help_text": "Projekt Tandoor Open Data dostarcza danych przesłanych przez społeczność dla Tandoor. To pole jest wypełniane automatycznie podczas importu i umożliwia aktualizacje w przyszłości.",
"Open_Data_Slug": "Open Data Slug",
"Open_Data_Import": "Open Data Import",
"Data_Import_Info": "Wzbogać swoją Przestrzeń, importując wyselekcjonowaną przez społeczność listę żywności, jednostek i nie tylko, aby ulepszyć swoją kolekcję przepisów.",
"Update_Existing_Data": "Zaktualizuj istniejące dane",
"Use_Metric": "Użyj jednostek metrycznych",
"Learn_More": "Dowiedz się więcej",
"converted_unit": "Przeliczona jednostka",
"converted_amount": "Przeliczona ilość",
"base_unit": "Jednostka podstawowa",
"base_amount": "Ilość bazowa",
"Datatype": "Typ danych",
"Number of Objects": "Ilość obiektów",
"Property": "Właściwość",
"Conversion": "Konwersja",
"Properties": "Właściwości",
"total": "łącznie",
"Welcome": "Witamy",
"g": "gram [g] (metryczny, waga)",
"ml": "mililitr [ml] (metryczny, objętość)",
"quart": "kwarta [qt] (USA, objętość)",
"imperial_fluid_ounce": "imperialna uncja płynu [imp fl oz] (WB, objętość)",
"imperial_tbsp": "imperialna łyżka stołowa [imp tbsp] (WB, objętość)",
"kg": "kilogram [kg] (metryczny, waga)",
"ounce": "uncja [oz] (waga)",
"pound": "funt (waga)",
"l": "litr [l] (metryczny, objętość)",
"fluid_ounce": "uncja płynu [fl oz] (USA, objętość)",
"gallon": "galon [gal] (USA, objętość)",
"tbsp": "łyżka stołowa [tbsp] (USA, objętość)",
"tsp": "łyżeczka [tsp] (USA, objętość)",
"imperial_pint": "pinta imperialna [imp pt] (WB, objętość)",
"pint": "pinta [pt] (USA, objętość)",
"imperial_quart": "kwarta imperialna [imp qt] (WB, objętość)",
"imperial_gallon": "imperialny galon [imp gal] (WB, objętość)",
"imperial_tsp": "łyżeczka imperialna [imp tsp] (WB, objętość)",
"Choose_Category": "Wybierz kategorię",
"Back": "Z powrotem",
"StartDate": "Data początkowa",
"OrderInformation": "Obiekty są uporządkowane od małych do dużych liczb.",
"show_ingredients_table": "Wyświetl tabelę składników obok tekstu kroku",
"Never_Unit": "Jednostka nigdy (??)",
"EndDate": "Data końcowa",
"show_step_ingredients_setting": "Pokaż składniki obok kroków przepisu",
"show_step_ingredients_setting_help": "Dodaj tabelę składników obok kroków przepisu. Dotyczy w momentu tworzenia. Można zmodyfikować w widoku edycji przepisu.",
"show_step_ingredients": "Pokaż składniki kroku",
"hide_step_ingredients": "Ukryj składniki kroku",
"Transpose_Words": "Transponuj słowa",
"Name_Replace": "Zastąp nazwę",
"Food_Replace": "Zastąp produkt",
"Unit_Replace": "Zastąp jednostkę",
"Alignment": "Wyrównanie"
}

View File

@ -382,7 +382,6 @@
"err_deleting_protected_resource": "O objeto que você está tentando deletar ainda está sendo utilizado, portanto não pode ser deletado.",
"food_inherit_info": "Campos no alimento que devem ser herdados por padrão.",
"warning_space_delete": "Pode eliminar o seu espaço incluindo todas as receitas, listas de compras, planos de refeição e tudo o que tenha criado. Isto não pode ser desfeito! Tem a certeza que quer fazer isto?",
"facet_count_info": "Mostrar quantidade de receitas nos filtros de busca.",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",

View File

@ -104,7 +104,7 @@
"Image": "Imagem",
"Delete": "Deletar",
"Open": "Abrir",
"Ok": "Abrir",
"Ok": "Ok",
"Save": "Salvar",
"Step": "Etapa",
"Search": "Buscar",
@ -333,21 +333,21 @@
"ingredient_list": "",
"explain": "",
"filter": "",
"search_no_recipes": "",
"search_import_help_text": "",
"search_create_help_text": "",
"warning_duplicate_filter": "",
"reset_children": "",
"reset_children_help": "",
"substitute_help": "",
"substitute_siblings_help": "",
"substitute_children_help": "",
"substitute_siblings": "",
"substitute_children": "",
"SubstituteOnHand": "",
"ChildInheritFields": "",
"ChildInheritFields_help": "",
"InheritFields_help": "",
"search_no_recipes": "Não encontrou nenhuma receita!",
"search_import_help_text": "Importe uma receita de um website externo ou aplicação.",
"search_create_help_text": "Crie uma nova receita diretamente em Tandoor.",
"warning_duplicate_filter": "Aviso: Por limitações técnicas, ter múltiplos filtros de uma mesma combinação (e, ou, não) pode ocasionar resultados inesperados.",
"reset_children": "Redefinir Herança Filho",
"reset_children_help": "Substitua todos os filhos por valores de campos herdados. Os campos herdados dos filhos serão definidos como Campos Herdados, a menos que Campos Herdados pelos Filhos esteja definido.",
"substitute_help": "Os substitutos são considerados na busca por receitas que possam ser feitas com ingredientes disponíveis.",
"substitute_siblings_help": "Todos os alimentos que compartilham um dos pais deste alimento são considerados substitutos.",
"substitute_children_help": "Todos os alimentos filhos deste alimento são considerados substitutos.",
"substitute_siblings": "Irmãos Substitutos",
"substitute_children": "Filhos Substitutos",
"SubstituteOnHand": "Você tem um substituto disponível.",
"ChildInheritFields": "Campos de Filhos Herdados",
"ChildInheritFields_help": "Os filhos herdarão esses campos por padrão.",
"InheritFields_help": "Os valores desses campos serão herdados do pai (Exceção: categorias de compras em branco não são herdadas)",
"last_viewed": "",
"created_on": "",
"updatedon": "",
@ -387,7 +387,6 @@
"Copy Token": "Copiar Token",
"warning_space_delete": "Você pode deletar seu espaço, inclusive todas as receitas, listas de mercado, planos de comida e tudo mais que você criou. Esta ação não poderá ser desfeita! Você tem certeza que quer fazer isto?",
"food_inherit_info": "Campos no alimento que devem ser herdados por padrão.",
"facet_count_info": "Mostrar quantidade de receitas nos filtros de busca.",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
@ -398,5 +397,15 @@
"Amount": "Quantidade",
"Description_Replace": "Substituir Descrição",
"Decimals": "Decimais",
"Instruction_Replace": "Substituir Instrução"
"Instruction_Replace": "Substituir Instrução",
"per_serving": "por porções",
"no_more_images_found": "Nenhuma imagem adicional encontrada no Website.",
"Auto_Sort": "Classificação automática",
"reset_food_inheritance": "Redefinir Herança",
"paste_json": "Cole JSON ou fonte HTML aqui para carregar receita.",
"recipe_property_info": "Você também pode adicionar propriedades às comidas para calcular elas automaticamente baseadas na sua receita!",
"import_duplicates": "Para evitar duplicatas, as receitas com o mesmo nome das existentes são ignoradas. Marque esta caixa para importar tudo.",
"Click_To_Edit": "Clique para editar",
"reset_food_inheritance_info": "Redefinir todas as comidas para campos herdados padrão e seus valores pai.",
"show_ingredients_table": "Exiba uma tabela de ingredientes ao lado do texto da etapa"
}

View File

@ -16,202 +16,467 @@
"convert_internal": "Transformați în rețetă internă",
"show_only_internal": "Arătați doar rețetele interne",
"show_split_screen": "Vedere divizată",
"Log_Recipe_Cooking": "",
"External_Recipe_Image": "",
"Add_to_Shopping": "",
"Add_to_Plan": "",
"Step_start_time": "",
"Sort_by_new": "",
"Table_of_Contents": "",
"Recipes_per_page": "",
"Show_as_header": "",
"Hide_as_header": "",
"Add_nutrition_recipe": "",
"Remove_nutrition_recipe": "",
"Copy_template_reference": "",
"Save_and_View": "",
"Manage_Books": "",
"Meal_Plan": "",
"Select_Book": "",
"Select_File": "",
"Recipe_Image": "",
"Import_finished": "",
"View_Recipes": "",
"Log_Cooking": "",
"New_Recipe": "",
"Url_Import": "",
"Reset_Search": "",
"Recently_Viewed": "",
"Load_More": "",
"New_Keyword": "",
"Delete_Keyword": "",
"Edit_Keyword": "",
"Edit_Recipe": "",
"Move_Keyword": "",
"Merge_Keyword": "",
"Hide_Keywords": "",
"Hide_Recipes": "",
"Move_Up": "",
"Move_Down": "",
"Step_Name": "",
"Step_Type": "",
"Make_Header": "",
"Make_Ingredient": "",
"Enable_Amount": "",
"Disable_Amount": "",
"Add_Step": "",
"Keywords": "",
"Books": "",
"Proteins": "",
"Fats": "",
"Carbohydrates": "",
"Calories": "",
"Energy": "",
"Nutrition": "",
"Date": "",
"Share": "",
"Automation": "",
"Parameter": "",
"Export": "",
"Copy": "",
"Rating": "",
"Close": "",
"Cancel": "",
"Link": "",
"Add": "",
"New": "",
"Note": "",
"Success": "",
"Failure": "",
"Ingredients": "",
"Supermarket": "",
"Categories": "",
"Category": "",
"Selected": "",
"min": "",
"Servings": "",
"Waiting": "",
"Preparation": "",
"External": "",
"Size": "",
"Files": "",
"File": "",
"Edit": "",
"Image": "",
"Delete": "",
"Open": "",
"Ok": "",
"Save": "",
"Step": "",
"Search": "",
"Import": "",
"Print": "",
"Settings": "",
"or": "",
"and": "",
"Information": "",
"Download": "",
"Create": "",
"Log_Recipe_Cooking": "Jurnalul rețetelor de pregătire",
"External_Recipe_Image": "Imagine rețetă externă",
"Add_to_Shopping": "Adaugare la cumpărături",
"Add_to_Plan": "Adăugare la plan",
"Step_start_time": "Pasule de începere a orei",
"Sort_by_new": "Sortare după nou",
"Table_of_Contents": "Cuprins",
"Recipes_per_page": "Rețete pe pagină",
"Show_as_header": "Afișare ca antet",
"Hide_as_header": "Ascunderea ca antet",
"Add_nutrition_recipe": "Adăugare a nutriției la rețetă",
"Remove_nutrition_recipe": "Ștergere a nutriției din rețetă",
"Copy_template_reference": "Copie referința șablonului",
"Save_and_View": "Salvare și vizionare",
"Manage_Books": "Gestionarea cărților",
"Meal_Plan": "Plan de alimentare",
"Select_Book": "Selectare carte",
"Select_File": "Selectare fișier",
"Recipe_Image": "Imagine a rețetei",
"Import_finished": "Importare finalizată",
"View_Recipes": "Vizionare rețete",
"Log_Cooking": "Jurnal de pregătire",
"New_Recipe": "Rețetă nouă",
"Url_Import": "Importă URL",
"Reset_Search": "Resetarea căutării",
"Recently_Viewed": "Vizualizate recent",
"Load_More": "Încărcați mai mult",
"New_Keyword": "Cuvânt cheie nou",
"Delete_Keyword": "Ștergere cuvânt cheie",
"Edit_Keyword": "Editează cuvânt cheie",
"Edit_Recipe": "Editează rețeta",
"Move_Keyword": "Mută cuvânt cheie",
"Merge_Keyword": "Unește cuvânt cheie",
"Hide_Keywords": "Ascunde cuvânt cheie",
"Hide_Recipes": "Ascunde rețetele",
"Move_Up": "Deplasați-vă în sus",
"Move_Down": "Deplasați-vă în jos",
"Step_Name": "Nume pas",
"Step_Type": "Tip pas",
"Make_Header": "Creare antet",
"Make_Ingredient": "Create ingredient",
"Enable_Amount": "Activare cantitate",
"Disable_Amount": "Dezactivare cantitate",
"Add_Step": "Adaugă pas",
"Keywords": "Cuvinte cheie",
"Books": "Cărți",
"Proteins": "Proteine",
"Fats": "Grăsimi",
"Carbohydrates": "Carbohidrați",
"Calories": "Calorii",
"Energy": "Energie",
"Nutrition": "Nutriție",
"Date": "Dată",
"Share": "Împărtășire",
"Automation": "Automatizare",
"Parameter": "Parametru",
"Export": "Exportă",
"Copy": "Copie",
"Rating": "Evaluare",
"Close": "Închide",
"Cancel": "Anulează",
"Link": "Link",
"Add": "Adaugă",
"New": "Nou",
"Note": "Notă",
"Success": "Succes",
"Failure": "Eșec",
"Ingredients": "Ingrediente",
"Supermarket": "Supermarket",
"Categories": "Categorii",
"Category": "Categorie",
"Selected": "Selectat",
"min": "min",
"Servings": "Porții",
"Waiting": "Așteptare",
"Preparation": "Pregătire",
"External": "Extern",
"Size": "Marime",
"Files": "Fișiere",
"File": "Fișier",
"Edit": "Editează",
"Image": "Imagine",
"Delete": "Șterge",
"Open": "Deschide",
"Ok": "Ok",
"Save": "Salvare",
"Step": "Pas",
"Search": "Căutare",
"Import": "Importă",
"Print": "Tipărește",
"Settings": "Setări",
"or": "sau",
"and": "și",
"Information": "Informație",
"Download": "Descarcă",
"Create": "Creează",
"Advanced Search Settings": "",
"View": "",
"Recipes": "",
"Move": "",
"Merge": "",
"Parent": "",
"delete_confirmation": "",
"move_confirmation": "",
"merge_confirmation": "",
"create_rule": "",
"move_selection": "",
"merge_selection": "",
"Root": "",
"Ignore_Shopping": "",
"Shopping_Category": "",
"Edit_Food": "",
"Move_Food": "",
"New_Food": "",
"Hide_Food": "",
"Food_Alias": "",
"Unit_Alias": "",
"Keyword_Alias": "",
"Delete_Food": "",
"No_ID": "",
"Meal_Plan_Days": "",
"merge_title": "",
"move_title": "",
"Food": "",
"Recipe_Book": "",
"del_confirmation_tree": "",
"delete_title": "",
"create_title": "",
"edit_title": "",
"Name": "",
"Type": "",
"Description": "",
"Recipe": "",
"tree_root": "",
"Icon": "",
"Unit": "",
"No_Results": "",
"New_Unit": "",
"Create_New_Shopping Category": "",
"Create_New_Food": "",
"Create_New_Keyword": "",
"Create_New_Unit": "",
"Create_New_Meal_Type": "",
"and_up": "",
"Instructions": "",
"Unrated": "",
"Automate": "",
"Empty": "",
"Key_Ctrl": "",
"Key_Shift": "",
"Time": "",
"Text": "",
"Shopping_list": "",
"Create_Meal_Plan_Entry": "",
"Edit_Meal_Plan_Entry": "",
"Title": "",
"Week": "",
"Month": "",
"Year": "",
"Planner": "",
"Planner_Settings": "",
"Period": "",
"Plan_Period_To_Show": "",
"Periods": "",
"Plan_Show_How_Many_Periods": "",
"Starting_Day": "",
"Meal_Types": "",
"Meal_Type": "",
"Clone": "",
"Drag_Here_To_Delete": "",
"Meal_Type_Required": "",
"Title_or_Recipe_Required": "",
"Color": "",
"New_Meal_Type": "",
"Week_Numbers": "",
"Show_Week_Numbers": "",
"Export_As_ICal": "",
"Export_To_ICal": "",
"Cannot_Add_Notes_To_Shopping": "",
"Added_To_Shopping_List": "",
"Shopping_List_Empty": "",
"Next_Period": "",
"Previous_Period": "",
"Current_Period": "",
"Next_Day": "",
"Previous_Day": "",
"Coming_Soon": "",
"Auto_Planner": "",
"New_Cookbook": "",
"Hide_Keyword": "",
"Clear": "",
"Plural": "",
"plural_short": "",
"Use_Plural_Unit_Always": "",
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"View": "Vizualizare",
"Recipes": "Rețete",
"Move": "Mută",
"Merge": "Unire",
"Parent": "Părinte",
"delete_confirmation": "Sunteți sigur că doriți să ștergeți {source}?",
"move_confirmation": "Mutare <i>{copil}</i> la părinte <i>{părinte}</i>",
"merge_confirmation": "Înlocuiți <i>{source}</i> cu <i>{target}</i>",
"create_rule": "și crearea automatizării",
"move_selection": "Selectați un părinte {type} pentru a muta {source} în.",
"merge_selection": "Înlocuiți toate aparițiile {source} cu {type} selectat.",
"Root": "Rădăcină",
"Ignore_Shopping": "Ignoră cumpărăturile",
"Shopping_Category": "Categorie de cumpărături",
"Edit_Food": "Editare mâncare",
"Move_Food": "Mutare mâncare",
"New_Food": "Mâncare nouă",
"Hide_Food": "Ascunde mâncare",
"Food_Alias": "Pseudonim mâncare",
"Unit_Alias": "Pseudonim unitate",
"Keyword_Alias": "Pseudonim cuvânt cheie",
"Delete_Food": "Ștergere mâncare",
"No_ID": "ID-ul nu a fost găsit, nu se poate șterge.",
"Meal_Plan_Days": "Planuri de alimentație pe viitor",
"merge_title": "Unire {type}",
"move_title": "Mutare {type}",
"Food": "Mâncare",
"Recipe_Book": "Carte de rețete",
"del_confirmation_tree": "Sunteți sigur că doriți să ștergeți {sursa} și toți copiii săi?",
"delete_title": "Ștergere {type}",
"create_title": "{type} nou",
"edit_title": "Editare {type}",
"Name": "Nume",
"Type": "Tip",
"Description": "Descriere",
"Recipe": "Rețetă",
"tree_root": "Rădăcina copacului",
"Icon": "Iconiță",
"Unit": "Unitate",
"No_Results": "Fără rezultate",
"New_Unit": "Unitate nouă",
"Create_New_Shopping Category": "Creați o nouă categorie de cumpărături",
"Create_New_Food": "Adaugă mâncare nouă",
"Create_New_Keyword": "Adaugă cuvânt cheie nou",
"Create_New_Unit": "Adaugă unitate nouă",
"Create_New_Meal_Type": "Adaugă tip mâncare nou",
"and_up": "& Sus",
"Instructions": "Instrucțiuni",
"Unrated": "Neevaluat",
"Automate": "Automatizat",
"Empty": "Gol",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Time": "Timp",
"Text": "Text",
"Shopping_list": "Lisă de cumpărături",
"Create_Meal_Plan_Entry": "Crearea înregistrării în planul de alimentare",
"Edit_Meal_Plan_Entry": "Editarea înregistrării în planul de alimentare",
"Title": "Titlu",
"Week": "Săptămână",
"Month": "Lună",
"Year": "An",
"Planner": "Planificator",
"Planner_Settings": "Setări planificator",
"Period": "Perioadă",
"Plan_Period_To_Show": "Afișați săptămâni, luni sau ani",
"Periods": "Perioade",
"Plan_Show_How_Many_Periods": "Câte perioade să afișezi",
"Starting_Day": "Ziua de început a săptămânii",
"Meal_Types": "Tipuri de mese",
"Meal_Type": "Tipul mesei",
"Clone": "Clonă",
"Drag_Here_To_Delete": "Mută aici pentru a șterge",
"Meal_Type_Required": "Tipul mesei este necesar",
"Title_or_Recipe_Required": "Titlul sau selecția rețetei necesare",
"Color": "Culoare",
"New_Meal_Type": "Tip de masă nou",
"Week_Numbers": "Numerele săptămânii",
"Show_Week_Numbers": "Afișați numerele săptămânii?",
"Export_As_ICal": "Exportul perioadei curente în format iCal",
"Export_To_ICal": "Exportă .ics",
"Cannot_Add_Notes_To_Shopping": "Notele nu pot fi adăugate la lista de cumpărături",
"Added_To_Shopping_List": "Adăugat la lista de cumpărături",
"Shopping_List_Empty": "Lista de cumpărături este în prezent goală, puteți adăuga articole prin meniul contextual al unei intrări în planul de alimentație (faceți click dreapta pe card sau faceți click stânga pe iconița meniului)",
"Next_Period": "Perioada următoare",
"Previous_Period": "Perioada precedentă",
"Current_Period": "Perioada curentă",
"Next_Day": "Ziua următoare",
"Previous_Day": "Ziua precedentă",
"Coming_Soon": "În curând",
"Auto_Planner": "Planificator automat",
"New_Cookbook": "Nouă carte de bucate",
"Hide_Keyword": "Ascunde cuvintele cheie",
"Clear": "Curățare",
"Plural": "Plural",
"plural_short": "plural",
"Use_Plural_Unit_Always": "Utilizarea formei plurale pentru unitate întotdeauna",
"Use_Plural_Unit_Simple": "Utilizarea dinamică a formei plurale pentru unitate",
"Use_Plural_Food_Always": "Utilizarea formei plurale pentru alimente întotdeauna",
"Use_Plural_Food_Simple": "Utilizarea dinamica a formei plurale pentru alimente",
"plural_usage_info": "Utilizarea formei plurale pentru unități și alimente în interiorul acestui spațiu.",
"last_viewed": "Ultima vizualizare",
"created_on": "Creat la data de",
"updatedon": "Actualizat la data de",
"Imported_From": "Importat din",
"and_down": "& Jos",
"Warning": "Atenționare",
"ShowDelayed": "Afișarea elementelor întârziate",
"shopping_share_desc": "Utilizatorii vor vedea toate articolele pe care le adăugați în lista de cumpărături. Ei trebuie să vă adauge pentru a vedea elementele din lista lor.",
"mealplan_autoinclude_related_desc": "Atunci când adăugați un plan de alimentare în lista de cumpărături (manual sau automat), includeți toate rețetele asociate.",
"SuccessClipboard": "Lista de cumpărături copiată în clipboard",
"in_shopping": "În lista de cumpărături",
"not": "nu",
"Pin": "Fixează",
"Create Recipe": "Crearea rețetei",
"Import Recipe": "Importă rețeta",
"csv_prefix_label": "Prefix a listei",
"Click_To_Edit": "Faceți click pentru a edita",
"Ingredient Editor": "Editor de ingrediente",
"FoodOnHand": "Aveți {food} la îndemână.",
"AddFoodToShopping": "Adăugă {food} în lista de cumpărături",
"New_Entry": "Înregistrare nouă",
"GroupBy": "Grupat de",
"CountMore": "...+{count} mai mult",
"IgnoreThis": "Nu adăugați niciodată automat {food} la cumpărături",
"InheritWarning": "{food} este setat să moștenească, este posibil ca modificările să nu persiste.",
"err_move_self": "Nu se poate muta elementul în sine",
"CategoryName": "Nume categorie",
"Foods": "Alimente",
"copy_to_new": "Copiere in rețetă nouă",
"reset_children": "Resetarea moștenirii copilului",
"err_moving_resource": "A existat o eroare în mutarea unei resurse!",
"err_merging_resource": "A existat o eroare la fuzionarea unei resurse!",
"success_moving_resource": "Resursă mutată cu succes!",
"success_merging_resource": "A fuzionat cu succes o resursă!",
"Decimals": "Zecimale",
"Default_Unit": "Unitate standard",
"Use_Fractions": "Folosire fracțiuni",
"Use_Fractions_Help": "Convertiți automat zecimalele în fracții atunci când vizualizați o rețetă.",
"RemoveFoodFromShopping": "Șterge {food} din lista de cumpărături",
"IgnoredFood": "{food} este setat să ignore cumpărăturile.",
"Add_Servings_to_Shopping": "Adăugă {servings} porții la cumpărături",
"InheritFields": "Moștenirea valorilor câmpurilor",
"Language": "Limba",
"Theme": "Tema",
"NoCategory": "Nicio categorie selectată.",
"OfflineAlert": "Sunteți offline, este posibil ca lista de cumpărături să nu se sincronizeze.",
"mealplan_autoinclude_related": "Adăugați rețete asociate",
"shopping_auto_sync": "Sincronizare automată",
"mealplan_autoadd_shopping": "Adăugare automată a planului de alimentare",
"default_delay": "Ore de întârziere implicite",
"plan_share_desc": "Noile intrări din Planul de alimentare vor fi partajate automat cu utilizatorii selectați.",
"shopping_auto_sync_desc": "Setarea la 0 va dezactiva sincronizarea automată. Atunci când vizualizați o listă de cumpărături, lista este actualizată la fiecare câteva secunde setate pentru a sincroniza modificările pe care altcineva le-ar fi putut face. Util atunci când faceți cumpărături cu mai multe persoane, dar va folosi mai multe date mobile.",
"mealplan_autoexclude_onhand_desc": "Atunci când adăugați un plan de alimentare în lista de cumpărături (manual sau automat), excludeți ingredientele care sunt în prezent la îndemână.",
"default_delay_desc": "Numărul implicit de ore pentru a întârzia o intrare în lista de cumpărături.",
"Hour": "Oră",
"Hours": "Ore",
"Day": "Zi",
"Days": "Zile",
"Second": "Secundă",
"Seconds": "Secunde",
"Users": "Utilizatori",
"Invites": "Invită",
"nothing": "Nimic de făcut",
"err_merge_self": "Nu se poate uni elementul cu el însuși",
"download_csv": "Descarcă CSV",
"Account": "Cont",
"Cosmetic": "Cosmetice",
"API": "API",
"left_handed_help": "Va optimiza interfața de utilizare pentru utilizare cu mâna stângă.",
"Custom Filter": "Filtru personalizat",
"recipe_name": "Nume rețetă",
"paste_ingredients": "Inserați ingredientele",
"Website": "Site web",
"Nav_Color_Help": "Modificare culoare navigare.",
"Use_Kj": "Utilizare kJ în loc de kcal",
"Username": "Nume utilizator",
"First_name": "Prenume",
"Last_name": "Nume de familie",
"Keyword": "Cuvânt cheie",
"Advanced": "Avansat",
"Page": "Pagină",
"User": "Utilizator",
"Shopping_Categories": "Categorii de cumpărături",
"Single": "Singur",
"Multiple": "Multiplu",
"Reset": "Resetare",
"Disabled": "Dezactivat",
"Disable": "Dezactivare",
"Importer_Help": "Mai multe informații și ajutor cu privire la acest importator:",
"Documentation": "Documentație",
"Import_Error": "A apărut o eroare în timpul importului. Vă rugăm să extindeți detaliile din partea de jos a paginii pentru a le vizualiza.",
"Warning_Delete_Supermarket_Category": "Ștergerea unei categorii de supermarketuri va șterge, de asemenea, toate relațiile cu alimentele. Sunteți sigur?",
"one_url_per_line": "O adresă URL pe linie",
"mealplan_autoexclude_onhand": "Excludeți alimentele la îndemână",
"shopping_recent_days": "Zilele recente",
"download_pdf": "Descarcă PDF",
"filter": "Filtru",
"Search Settings": "Setări de căutare",
"err_deleting_protected_resource": "Obiectul pe care încercați să îl ștergeți este încă utilizat și nu poate fi șters.",
"csv_delim_help": "Delimitatorul utilizat pentru exporturile CSV.",
"csv_delim_label": "Delimitatorul CSV",
"SupermarketCategoriesOnly": "Numai categorii de supermarket-uri",
"shopping_category_help": "Supermarket-urile pot fi ordonate și filtrate în funcție de categoria de cumpărături în conformitate cu aspectul culoarului.",
"food_recipe_help": "Legarea unei rețete aici va include rețeta legată în orice altă rețetă care utilizează acest aliment",
"Private_Recipe": "Rețetă privată",
"DelayUntil": "Amână până la",
"shared_with": "Împărtășit cu",
"asc": "Crescător",
"desc": "Descrescător",
"date_viewed": "Ultimul vizionat",
"show_sortby": "Afișează sortat de",
"Quick actions": "Acțiuni rapide",
"Internal": "Intern",
"parameter_count": "Parametru {count}",
"Ratings": "Evaluări",
"warning_space_delete": "Puteți șterge spațiul, inclusiv toate rețetele, listele de cumpărături, planurile de alimentare și orice altceva ați creat. Acest lucru nu poate fi anulat! Sunteți sigur că doriți să faceți acest lucru?",
"remember_hours": "Ore de reținut",
"tree_select": "Utilizarea selecției arborilor",
"last_cooked": "Ultimul pregătit",
"Auto_Sort": "Sortare automatizată",
"Private_Recipe_Help": "Rețeta este arătată doar ție și oamenilor cu care este împărtășită.",
"save_filter": "Salvare filtru",
"Nav_Color": "Culoare navigare",
"Comments_setting": "Afișează comentarii",
"search_no_recipes": "Nu a putut găsi nici o rețetă!",
"Supermarkets": "Supermarket-uri",
"Undefined": "Nedefinit",
"Select": "Selectare",
"food_inherit_info": "Câmpuri pe alimente care ar trebui să fie moștenite în mod implicit.",
"Amount": "Cantitate",
"Auto_Sort_Help": "Mutați toate ingredientele la cel mai potrivit pas.",
"search_create_help_text": "Creați o rețetă nouă direct în Tandoor.",
"reusable_help_text": "Ar trebui link-ul de invitație să poată fi utilizat de mai mulți utilizatori.",
"Copy Link": "Copiere link",
"AddToShopping": "Adaugă la lista de cumpărături",
"FoodNotOnHand": "Nu aveți {food} la îndemână.",
"DeleteShoppingConfirm": "Sunteți sigur că doriți să eliminați toate {food} din lista de cumpărături?",
"mealplan_autoadd_shopping_desc": "Adăugați automat ingredientele planului de alimentare în lista de cumpărături.",
"filter_to_supermarket_desc": "În mod implicit, filtrați lista de cumpărături pentru a include numai categoriile pentru supermarketul selectat.",
"CategoryInstruction": "Trageți categoriile pentru a schimba categoriile de comenzi care apar în lista de cumpărături.",
"copy_markdown_table": "Copiere ca tabel Markdown",
"sql_debug": "Depanare SQL",
"remember_search": "Rețineți căutarea",
"OnHand_help": "Alimentele sunt în inventar și nu vor fi adăugate automat la o listă de cumpărături. Starea la îndemână este partajată cu utilizatorii de cumpărături.",
"show_rating": "Afișează evaluarea",
"search_rank": "Rang de căutare",
"book_filter_help": "Includeți rețete din filtrul de rețete în plus față de cele atribuite manual.",
"Sticky_Nav_Help": "Afișați întotdeauna meniul de navigare din partea de sus a ecranului.",
"import_duplicates": "Pentru a preveni duplicatele, rețetele cu același nume ca și cele existente sunt ignorate. Bifați această casetă pentru a importa totul.",
"warning_duplicate_filter": "Atenționare: Din cauza limitărilor tehnice care au mai multe filtre de aceeași combinație (și/sau/nu) ar putea da rezultate neașteptate.",
"substitute_help": "Înlocuitorii sunt luați în considerare atunci când căutați rețete care pot fi făcute cu ingrediente la îndemână.",
"substitute_children": "Înlocuire copii",
"SubstituteOnHand": "Ai un înlocuitor la îndemână.",
"InheritFields_help": "Valorile acestor câmpuri vor fi moștenite de la părinte (Excepție: categoriile de cumpărături necompletate nu sunt moștenite)",
"Social_Authentication": "Autentificare socială",
"empty_list": "Lista este goală.",
"Select_App_To_Import": "Selectați o aplicație din care să importați",
"Recipes_In_Import": "Rețete în fișierul de import",
"Split_All_Steps": "Împărțiți toate rândurile în pași separați.",
"Description_Replace": "Înlocuire descripție",
"Instruction_Replace": "Înlocuire instrucții",
"Copy Token": "Copiere token",
"ShowUncategorizedFood": "Afișează nedefinit",
"MoveCategory": "Mută la: ",
"DelayFor": "Întârziere pentru {hours} ore",
"Completed": "Completat",
"shopping_share": "Partajați lista de cumpărături",
"filter_to_supermarket": "Filtrați la supermarket",
"show_sql": "Afișează SQL",
"SupermarketName": "Numele supermarketului",
"FoodInherit": "Câmpuri moștenite de alimente",
"mark_complete": "Marcare completată",
"shopping_add_onhand_desc": "Marcați mâncarea 'La îndemână' atunci când este bifată de pe lista de cumpărături.",
"shopping_add_onhand": "La îndemână automat",
"related_recipes": "Rețete înrudite",
"ignore_shopping_help": "Nu adăugați niciodată alimente pe lista de cumpărături (ex. apă)",
"today_recipes": "Rețete de astăzi",
"enable_expert": "Activarea modului Expert",
"expert_mode": "Modul Expert",
"simple_mode": "Modul Simplu",
"advanced": "Avansat",
"Unpin": "Anularea fixării",
"Protected": "Protejat",
"Original_Text": "Text original",
"Create_New_Shopping_Category": "Adaugă categorie de cumpărături nouă",
"Added_by": "Adăugat de",
"Added_on": "Adăugat la",
"IngredientInShopping": "Acest ingredient se află în lista de cumpărături.",
"NotInShopping": "{food} nu se află în lista de cumpărături.",
"OnHand": "În prezent, la îndemână",
"Inherit": "Moștenire",
"shopping_recent_days_desc": "Zile de intrări recente lista de cumpărături pentru a afișa.",
"copy_to_clipboard": "Copierea în Clipboard",
"csv_prefix_help": "Prefix de adăugat la copierea listei în clipboard.",
"PinnedConfirmation": "{recipe} a fost fixată.",
"UnpinnedConfirmation": "Fixarea {recipe} a fost anulată.",
"QuickEntry": "Înscriere rapidă",
"fields": "Câmpuri",
"show_keywords": "Afișează cuvinte cheie",
"show_foods": "Afișează mâncări",
"show_books": "Afișează cărți",
"show_units": "Afișează unitățile",
"show_filters": "Afișează filtrele",
"filter_name": "Nume filtru",
"left_handed": "Modul stângaci",
"sort_by": "Sortat de",
"times_cooked": "Ori pregătite",
"date_created": "Data creării",
"make_now": "Creează acum",
"recipe_filter": "Filtru rețete",
"review_shopping": "Examinați intrările de cumpărături înainte de a salva",
"view_recipe": "Vizionează rețeta",
"paste_ingredients_placeholder": "Inserați lista de ingrediente aici...",
"ingredient_list": "Lista de ingrediente",
"explain": "Explicație",
"App": "Aplicație",
"Message": "Mesaj",
"Sticky_Nav": "Navigare lipicioasă",
"click_image_import": "Faceți click pe imaginea pe care doriți să o importați pentru această rețetă",
"no_more_images_found": "Nu există imagini suplimentare găsite pe site-ul web.",
"paste_json": "Inserați sursă JSON sau HTML aici pentru a încărca rețetă.",
"search_import_help_text": "Importați o rețetă de pe un site web sau o aplicație externă.",
"reset_children_help": "Suprascrieți toți copiii cu valori din câmpurile moștenite. Câmpurile moștenite ale copiilor vor fi setate la câmpuri standard, cu excepția cazului în care sunt setate câmpurile moștenite de copii.",
"reset_food_inheritance": "Resetați moștenirea",
"reset_food_inheritance_info": "Resetați toate alimentele la câmpurile moștenite implicit și la valorile părinte ale acestora.",
"substitute_siblings_help": "Toate alimentele care împărtășesc un părinte al acestui aliment sunt considerate înlocuitori.",
"substitute_children_help": "Toate alimentele care sunt copii ai acestui aliment sunt considerate înlocuitori.",
"substitute_siblings": "Înlocuire frați",
"Bookmarklet": "Marcaj",
"ChildInheritFields": "Copiii moștenesc câmpurile",
"ChildInheritFields_help": "Copiii vor moșteni aceste câmpuri în mod implicit.",
"show_ingredient_overview": "Afișați o listă cu toate ingredientele la începutul rețetei.",
"Ingredient Overview": "Prezentare generală a ingredientelor",
"advanced_search_settings": "Setări avansate de căutare",
"nothing_planned_today": "Nu ai nimic planificat pentru ziua de azi!",
"no_pinned_recipes": "Nu ai rețete fixate!",
"Planned": "Planificate",
"Pinned": "Fixate",
"Imported": "Importate",
"Units": "Unități",
"Manage_Emails": "Gestionarea e-mailurilor",
"Change_Password": "Schimbați parola",
"Random Recipes": "Rețete aleatoare",
"select_keyword": "Selectați cuvânt cheie",
"add_keyword": "Adăugare cuvânt cheie",
"select_file": "Selectare fișier",
"select_recipe": "Selectare rețetă",
"select_unit": "Selectare unitate",
"select_food": "Selectare mâncare",
"remove_selection": "Deselectare",
"Options": "Opțiuni",
"Create Food": "Creare mâncare",
"create_food_desc": "Creați un aliment și conectați-l la această rețetă.",
"additional_options": "Opțiuni suplimentare",
"Import_Supported": "Import compatibil",
"Export_Supported": "Export compatibil",
"Import_Not_Yet_Supported": "Importul încă nu este compatibil",
"Export_Not_Yet_Supported": "Exportul încă nu este compatibil",
"Import_Result_Info": "{imported} din {total} rețete au fost importate",
"Toggle": "Comutare",
"New_Supermarket": "Creați un supermarket nou",
"New_Supermarket_Category": "Creați o nouă categorie de supermarket-uri",
"Are_You_Sure": "Sunteți sigur?",
"Valid Until": "Valabil până la",
"Combine_All_Steps": "Combinați toți pașii într-un singur câmp."
}

View File

@ -1,11 +1,11 @@
{
"warning_feature_beta": "Данный функционал находится в сдадии BETA (тестируется). Возможны баги и серьезные изменения функционала в будующем.",
"warning_feature_beta": "Данный функционал находится в стадии BETA (тестируется). Возможны баги и серьезные изменения функционала в будущем.",
"err_fetching_resource": "Ошибка при загрузке продукта!",
"err_creating_resource": "Ошибка при создании продукта!",
"err_updating_resource": "Ошибка при редактировании продукта!",
"err_deleting_resource": "Ошибка при удалении продукта!",
"success_fetching_resource": "Продукт успешно загружен!",
"success_creating_resource": "Продукт успешно загружен!",
"success_creating_resource": "Продукт успешно создан!",
"success_updating_resource": "Продукт успешно обновлен!",
"success_deleting_resource": "Продукт успешно удален!",
"file_upload_disabled": "Выгрузка файла не активирована в настройках.",
@ -13,7 +13,7 @@
"confirm_delete": "Вы уверены, что хотите удалить этот объект?",
"import_running": "Идет загрузка, пожалуйста ждите!",
"all_fields_optional": "Все поля не обязательны для заполнения.",
"convert_internal": "Конвретировать рецепт во внутренний формат",
"convert_internal": "Конвертировать рецепт во внутренний формат",
"show_only_internal": "Показывать только рецепты во внутреннем формате",
"show_split_screen": "Двухколоночный вид",
"Log_Recipe_Cooking": "Журнал приготовления",
@ -211,13 +211,13 @@
"FoodNotOnHand": "{food} отсутствует в наличии.",
"Undefined": "Неизвестно",
"AddFoodToShopping": "Добавить {food} в ваш список покупок",
"success_moving_resource": "Успешное перемещение ресурса!",
"success_merging_resource": "Ресурс успешно присоединен!",
"success_moving_resource": "Успешное перемещение продукта!",
"success_merging_resource": "Продукт успешно присоединен!",
"Shopping_Categories": "Категории покупок",
"Search Settings": "Искать настройки",
"err_merging_resource": "Произошла ошибка при перемещении ресурса!",
"err_merging_resource": "Произошла ошибка при перемещении продукта!",
"Remove_nutrition_recipe": "Уберите питательные вещества из рецепта",
"err_moving_resource": "Произошла ошибка при перемещении ресурса!",
"err_moving_resource": "Произошла ошибка при перемещении продукта!",
"NotInShopping": "{food} отсутствует в вашем списке покупок.",
"RemoveFoodFromShopping": "Удалить {food} из вашего списка покупок",
"ShowDelayed": "Показать отложенные элементы",
@ -286,7 +286,7 @@
"expert_mode": "Экспертный режим",
"enable_expert": "Включить экспертный режим",
"review_shopping": "Просмотрите записи о покупках перед сохранением",
"empty_list": "Список пуст",
"empty_list": "Список пуст.",
"default_delay_desc": "Число часов по умолчанию для отсрочки записи в списке покупок.",
"one_url_per_line": "Один URL в строке",
"mealplan_autoinclude_related": "Добавить сопутствующие рецепты",
@ -343,5 +343,7 @@
"DelayFor": "Отложить на {hours} часов",
"New_Entry": "Новая запись",
"GroupBy": "Сгруппировать по",
"facet_count_info": "Показывать количество рецептов в фильтрах поиска."
"food_inherit_info": "Поля для продуктов питания, которые должны наследоваться по умолчанию.",
"warning_space_delete": "Вы можете удалить свое пространство, включая все рецепты, списки покупок, планы питания и все остальное, что вы создали. Этого нельзя отменить! Вы уверены, что хотите это сделать?",
"Description_Replace": "Изменить описание"
}

View File

@ -291,5 +291,30 @@
"Use_Plural_Unit_Simple": "",
"Use_Plural_Food_Always": "",
"Use_Plural_Food_Simple": "",
"plural_usage_info": ""
"plural_usage_info": "",
"err_deleting_protected_resource": "Predmet, ki ga želite izbrisati, je še vedno v uporabi in ga ni mogoče izbrisati.",
"Private_Recipe": "Zasebni Recept",
"Private_Recipe_Help": "Recept je prikazan samo vam in osebam, s katerimi ga delite.",
"reusable_help_text": "Ali lahko povezavo za povabilo uporabi več kot en uporabnik.",
"Auto_Sort": "Samodejno Razvrščanje",
"Auto_Sort_Help": "Vse sestavine prestavi v najprimernejši korak.",
"food_inherit_info": "Polja za živila, ki so privzeto podedovana.",
"Description_Replace": "Zamenjaj Opis",
"recipe_property_info": "Živilom lahko dodate tudi lastnosti, ki se samodejno izračunajo na podlagi vašega recepta!",
"warning_space_delete": "Izbrišete lahko svoj prostor, vključno z vsemi recepti, nakupovalnimi seznami, načrti obrokov in vsem drugim, kar ste ustvarili. Tega ni mogoče preklicati! Ste prepričani, da želite to storiti?",
"per_serving": "na porcijo",
"Ingredient Editor": "Urejevalnik Sestavin",
"Instruction_Replace": "Zamenjaj Navodila",
"open_data_help_text": "Projekt Tandoor Open Data zagotavlja podatke, ki jih je prispeva skupnost. To polje se samodejno izpolni ob uvozu in omogoča posodobitve v prihodnosti.",
"Open_Data_Slug": "Open Data Identifikator",
"Open_Data_Import": "Open Data Uvoz",
"Data_Import_Info": "Izboljšajte svoj prostor z uvozom seznama živil, enot in drugega, ker je pripravila skupnost, ter s tem izboljšajte svojo zbirko receptov.",
"Update_Existing_Data": "Posodobitev Obstoječih Podatkov",
"Use_Metric": "Uporaba Metričnih Enot",
"Learn_More": "Preberite Več",
"converted_unit": "Pretvorjena Enota",
"converted_amount": "Pretvorjena Količina",
"base_unit": "Osnovna Enota",
"base_amount": "Osnovna Količina",
"Amount": "Količina"
}

View File

@ -425,7 +425,6 @@
"reusable_help_text": "Bör inbjudningslänken vara användbar för mer än en användare.",
"Ingredient Editor": "Ingrediensredigerare",
"warning_space_delete": "Du kan ta bort ditt utrymme inklusive alla recept, inköpslistor, måltidsplaner och allt annat du har skapat. Detta kan inte ångras! Är du säker på att du vill göra detta?",
"facet_count_info": "Visa recept antal på sökfilter.",
"food_inherit_info": "Fält på mat som ska ärvas som standard.",
"Auto_Sort": "Automatisk Sortering",
"Day": "Dag",

View File

@ -16,7 +16,6 @@
"file_upload_disabled": "Alanınız için dosya yükleme aktif değil.",
"warning_space_delete": "Tüm tarifler, alışveriş listeleri, yemek planları ve oluşturduğunuz her şey dahil olmak üzere silinecektir. Bu geri alınamaz! Bunu yapmak istediğinizden emin misiniz?",
"food_inherit_info": "",
"facet_count_info": "",
"step_time_minutes": "Dakika olarak adım süresi",
"confirm_delete": "",
"import_running": "",

View File

@ -421,7 +421,6 @@
"Use_Plural_Food_Simple": "",
"plural_usage_info": "",
"warning_space_delete": "Ви можете видалити ваш простір разом зі всіма рецептами, списками покупок, планами харчування і всім іншим, що ви створили. Ця дія незворотня! Ви впевнені, що бажаєте це зробити?",
"facet_count_info": "Показати кількість рецептів на полі пошуку.",
"Amount": "Кількість",
"Auto_Sort": "Автоматичне сортування",
"Auto_Sort_Help": "Перемістити всі інгредієнти до більш підходящого кроку.",

View File

@ -414,7 +414,6 @@
"Warning_Delete_Supermarket_Category": "删除超市类别也会删除与食品的所有关系。 你确定吗?",
"New_Supermarket": "创建新超市",
"warning_space_delete": "您可以删除您的空间,包括所有食谱、购物清单、膳食计划以及您创建的任何其他内容。 这不能被撤消! 你确定要这么做吗 ",
"facet_count_info": "在搜索筛选器上显示食谱计数。",
"Hide_as_header": "隐藏标题",
"food_inherit_info": "默认情况下应继承的食物上的字段。",
"Custom Filter": "自定义筛选器",
@ -479,5 +478,7 @@
"Auto_Sort": "自动分类",
"Auto_Sort_Help": "将所有食材移动到最恰当的步骤。",
"Create Recipe": "创建食谱",
"Import Recipe": "导入食谱"
"Import Recipe": "导入食谱",
"recipe_property_info": "您也可以为食物添加属性,以便根据食谱自动计算!",
"per_serving": "每份"
}

View File

View File

@ -2,6 +2,7 @@ import {defineStore} from 'pinia'
import {ApiApiFactory} from "@/utils/openapi/api";
const _STORE_ID = 'meal_plan_store'
const _LOCAL_STORAGE_KEY = 'MEAL_PLAN_CLIENT_SETTINGS'
import Vue from "vue"
import {StandardToasts} from "@/utils/utils";
/*
@ -12,6 +13,7 @@ export const useMealPlanStore = defineStore(_STORE_ID, {
state: () => ({
plans: {},
currently_updating: null,
settings: null,
}),
getters: {
plan_list: function () {
@ -23,7 +25,8 @@ export const useMealPlanStore = defineStore(_STORE_ID, {
},
empty_meal_plan: function () {
return {
date: null,
from_date: null,
to_date: null,
id: -1,
meal_type: null,
note: "",
@ -34,6 +37,12 @@ export const useMealPlanStore = defineStore(_STORE_ID, {
title: "",
title_placeholder: 'Title', // meal plan edit modal should be improved to not need this
}
},
client_settings: function () {
if (this.settings === null) {
this.settings = this.loadClientSettings()
}
return this.settings
}
},
actions: {
@ -84,6 +93,23 @@ export const useMealPlanStore = defineStore(_STORE_ID, {
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
})
},
updateClientSettings(settings) {
this.settings = settings
localStorage.setItem(_LOCAL_STORAGE_KEY, JSON.stringify(this.settings))
},
loadClientSettings() {
let s = localStorage.getItem(_LOCAL_STORAGE_KEY)
if (s === null || s === {}) {
return {
displayPeriodUom: "week",
displayPeriodCount: 3,
startingDayOfWeek: 1,
displayWeekNumbers: true,
}
} else {
return JSON.parse(s)
}
}
},
})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
* Django Recipes
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.0.0
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -4,7 +4,7 @@
* Django Recipes
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 0.0.0
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View File

@ -14,6 +14,7 @@ import {BToast} from "bootstrap-vue"
// * */
import Vue from "vue"
import {Actions, Models} from "./models"
import moment from "moment";
export const ToastMixin = {
name: "ToastMixin",
@ -50,7 +51,7 @@ export class StandardToasts {
static FAIL_MOVE = "FAIL_MOVE"
static FAIL_MERGE = "FAIL_MERGE"
static makeStandardToast(context, toast, err) {
static makeStandardToast(context, toast, err = undefined, always_show_errors = false) {
let title = ''
let msg = ''
let variant = ''
@ -124,11 +125,14 @@ export class StandardToasts {
}
let DEBUG = localStorage.getItem("DEBUG") === "True" || false
let DEBUG = localStorage.getItem("DEBUG") === "True" || always_show_errors
if (DEBUG){
console.log('ERROR ', err, JSON.stringify(err?.response?.data))
console.trace();
}
if (err !== undefined && 'response' in err && 'headers' in err.response) {
if (DEBUG && err.response.headers['content-type'] === 'application/json' && err.response.status < 500) {
console.log('ERROR ', JSON.stringify(err.response.data))
msg = context.$createElement('div', {}, [
context.$createElement('span', {}, [msg]),
context.$createElement('br', {}, []),
@ -311,7 +315,7 @@ export function calculateHourMinuteSplit(amount) {
let minutes = amount - hours * 60
let output_text = hours + " h"
if (minutes > 0){
if (minutes > 0) {
output_text += " " + minutes + " min"
}
@ -368,6 +372,9 @@ export const ApiMixin = {
let func = setup.function
let parameters = buildParams(options, setup)
let apiClient = new ApiApiFactory()
if (model.apiClient !== undefined) {
apiClient = model.apiClient
}
return apiClient[func](...parameters)
},
genericGetAPI: function (url, options) {
@ -718,6 +725,10 @@ export const formFunctions = {
form.fields.filter((x) => x.field === "inherit_fields")[0].value = getUserPreference("food_inherit_default")
return form
},
InviteLinkDefaultValid: function (form){
form.fields.filter((x) => x.field === "valid_until")[0].value = moment().add(7, "days").format('yyyy-MM-DD')
return form
},
AutomationOrderDefault: function (form) {
if (form.fields.filter((x) => x.field === "order")[0].value === undefined) {
form.fields.filter((x) => x.field === "order")[0].value = 1000