Compare commits

...

21 Commits

Author SHA1 Message Date
vabene1111
9119d773f1 Merge branch 'develop' 2025-07-31 19:28:03 +02:00
vabene1111
4ea5cdb8b9 Merge branch 'develop' of https://github.com/TandoorRecipes/recipes into develop 2025-07-31 19:27:56 +02:00
vabene1111
f36e5f1d89 re-enabled latest push 2025-07-31 19:27:51 +02:00
Justin Straver
bce95ff604 Translated using Weblate (Slovenian)
Currently translated at 99.6% (794 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sl/
2025-07-31 17:26:43 +00:00
Justin Straver
0f0a5b32cd Translated using Weblate (Dutch)
Currently translated at 99.4% (793 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2025-07-31 17:26:43 +00:00
Justin Straver
0bd0b794df Translated using Weblate (Spanish)
Currently translated at 95.6% (762 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/es/
2025-07-31 17:26:43 +00:00
Justin Straver
5267ac12b0 Translated using Weblate (German)
Currently translated at 99.1% (790 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2025-07-31 17:26:43 +00:00
Justin Straver
02678ffe30 Translated using Weblate (English)
Currently translated at 100.0% (797 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/en/
2025-07-31 17:26:43 +00:00
Justin Straver
2907e29a11 Translated using Weblate (Dutch)
Currently translated at 99.2% (791 of 797 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2025-07-31 16:42:55 +00:00
vabene1111
9d49c4d550 Merge branch 'develop' of http://translate.tandoor.dev/git/tandoor/recipes-backend into develop
# Conflicts:
#	vue3/src/locales/it.json
#	vue3/src/locales/ru.json
2025-07-31 18:04:43 +02:00
vabene1111
e2c6eec628 updated release flow 2025-07-31 17:52:47 +02:00
vabene1111
63716e4397 removed debug code 2025-07-31 17:43:42 +02:00
vabene1111
27e5955c78 Merge branch 'develop' 2025-07-31 17:29:28 +02:00
vabene1111
e9e6cdccca improved help page and dialog 2025-07-31 17:28:36 +02:00
vabene1111
8c8096e348 add ability to disable frontend plugins 2025-07-31 16:17:28 +02:00
vabene1111
9fcbbc17e8 port change logic 2025-07-31 16:04:30 +02:00
vabene1111
0a2f83cf85 localhost in nginx config 2025-07-31 15:49:48 +02:00
vabene1111
01fff0783f additions to help page 2025-07-29 18:04:40 +02:00
Aleksey
9b581d58bd Translated using Weblate (Russian)
Currently translated at 100.0% (795 of 795 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/ru/
2025-07-28 17:58:41 +00:00
Vincenzo Reale
79db8a2fe0 Translated using Weblate (Italian)
Currently translated at 100.0% (795 of 795 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/it/
2025-07-28 17:58:41 +00:00
Aleksey
f722d4751b Translated using Weblate (Russian)
Currently translated at 17.4% (85 of 488 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ru/
2025-07-28 17:58:40 +00:00
17 changed files with 6040 additions and 5512 deletions

View File

@@ -74,9 +74,8 @@ jobs:
flavor: |
latest=false
suffix=${{ matrix.suffix }}
# disable latest for tagged releases while in beta
# type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
tags: |
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
@@ -94,29 +93,29 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
# notify-stable:
# name: Notify Stable
# runs-on: ubuntu-latest
# needs: build-container
# if: startsWith(github.ref, 'refs/tags/')
# steps:
# - name: Set tag name
# run: |
# # Strip "refs/tags/" prefix
# echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
# # Send stable discord notification
# - name: Discord notification
# env:
# DISCORD_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
# uses: Ilshidur/action-discord@0.3.2
# with:
# args: '🚀 Version {{ VERSION }} of tandoor has been released 🥳 Check it out https://github.com/vabene1111/recipes/releases/tag/{{ VERSION }}'
notify-stable:
name: Notify Stable
runs-on: ubuntu-latest
needs: build-container
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Set tag name
run: |
# Strip "refs/tags/" prefix
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
# Send stable discord notification
- name: Discord notification
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
uses: Ilshidur/action-discord@0.3.2
with:
args: '🚀 Version {{ VERSION }} of tandoor has been released 🥳 Check it out https://github.com/vabene1111/recipes/releases/tag/{{ VERSION }}'
notify-beta:
name: Notify Beta
runs-on: ubuntu-latest
needs: build-container
if: startsWith(github.ref, 'refs/tags/')
if: github.ref == 'refs/heads/beta'
steps:
# Send beta discord notification
- name: Discord notification

View File

@@ -6,6 +6,11 @@ GUNICORN_WORKERS="${GUNICORN_WORKERS:-3}"
GUNICORN_THREADS="${GUNICORN_THREADS:-2}"
GUNICORN_LOG_LEVEL="${GUNICORN_LOG_LEVEL:-'info'}"
if [ "${TANDOOR_PORT}" -eq 80 ]; then
echo "TANDOOR_PORT set to 8080 because 80 is now taken by the integrated nginx"
TANDOOR_PORT=8080
fi
display_warning() {
echo "[WARNING]"
echo -e "$1"

View File

@@ -176,7 +176,6 @@ class IngredientParser:
# if something like this is detected move it to the beginning so the parser can handle it
if len(ingredient) < 1000 and re.search(r'^([^\W\d_])+(.)*[1-9](\d)*\s*([^\W\d_])+', ingredient):
match = re.search(r'[1-9](\d)*\s*([^\W\d_])+', ingredient)
print(f'reording from {ingredient} to {ingredient[match.start():match.end()] + " " + ingredient.replace(ingredient[match.start():match.end()], "")}')
ingredient = ingredient[match.start():match.end()] + ' ' + ingredient.replace(ingredient[match.start():match.end()], '')
# if the string contains parenthesis early on remove it and place it at the end
@@ -284,6 +283,4 @@ class IngredientParser:
if len(food.strip()) == 0:
raise ValueError(f'Error parsing string {ingredient}, food cannot be empty')
print(f'parsed {ingredient} to {amount} - {unit} - {food} - {note}')
return amount, unit, food, note[:Ingredient._meta.get_field('note').max_length].strip()

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2024-11-12 17:58+0000\n"
"Last-Translator: Владислав <vlad@kelonmyosa.ru>\n"
"PO-Revision-Date: 2025-07-28 17:58+0000\n"
"Last-Translator: Aleksey <streltsov3@gmail.com>\n"
"Language-Team: Russian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/ru/>\n"
"Language: ru\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.6.2\n"
"X-Generator: Weblate 5.8.4\n"
#: .\cookbook\forms.py:45
msgid ""
@@ -90,22 +90,24 @@ msgid ""
"<a href=\"https://www.home-assistant.io/docs/authentication/#your-account-"
"profile\">Long Lived Access Token</a> for your HomeAssistant instance"
msgstr ""
"<a href=\"https://www.home-assistant.io/docs/authentication/#your-account-"
"profile\">Длительный токен доступа</a> для вашей установки HomeAssistant"
#: .\cookbook\forms.py:193
msgid "Something like http://homeassistant.local:8123/api"
msgstr ""
msgstr "Что-то вроде http://homeassistant.local:8123/api"
#: .\cookbook\forms.py:205
msgid "http://homeassistant.local:8123/api for example"
msgstr ""
msgstr "Например, http://homeassistant.local:8123/api"
#: .\cookbook\forms.py:222 .\cookbook\views\edit.py:117
msgid "Storage"
msgstr ""
msgstr "Хранилище"
#: .\cookbook\forms.py:222
msgid "Active"
msgstr ""
msgstr "Активный"
#: .\cookbook\forms.py:226
msgid "Search String"
@@ -125,16 +127,12 @@ msgid "Email address already taken!"
msgstr "Этот email уже используется!"
#: .\cookbook\forms.py:275
#, fuzzy
#| msgid ""
#| "An email address is not required but if present the invite link will be "
#| "send to the user."
msgid ""
"An email address is not required but if present the invite link will be sent "
"to the user."
msgstr ""
"email не требуется, но если он присутствует, пользователю будет отправлена "
"ссылка для приглашения."
"Адрес электронной почты не обязателен, но если он указан, ссылка-приглашение "
"будет отправлена пользователю."
#: .\cookbook\forms.py:287
msgid "Name already taken."
@@ -149,6 +147,9 @@ msgid ""
"Determines how fuzzy a search is if it uses trigram similarity matching (e."
"g. low values mean more typos are ignored)."
msgstr ""
"Определяет степень нечёткости поиска при использовании сопоставления по "
"триграммам (например, низкие значения означают, что больше опечаток "
"игнорируется)."
#: .\cookbook\forms.py:340
#, fuzzy
@@ -183,24 +184,33 @@ msgid ""
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
"'pie' and 'piece' and 'soapie')"
msgstr ""
"Поля для поиска по частичному совпадению. (например, поиск по слову «Pie» "
"вернёт «pie», «piece» и «soapie»)"
#: .\cookbook\forms.py:344
msgid ""
"Fields to search for beginning of word matches. (e.g. searching for 'sa' "
"will return 'salad' and 'sandwich')"
msgstr ""
"Поля для поиска по совпадению начала слова. (например, поиск по «sa» вернёт "
"«salad» и «sandwich»)"
#: .\cookbook\forms.py:345
msgid ""
"Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) "
"Note: this option will conflict with 'web' and 'raw' methods of search."
msgstr ""
"Поля для нечёткого поиска. (например, поиск по слову «recpie» найдёт "
"«recipe»). Примечание: эта опция конфликтует с методами поиска «web» и "
"«raw»."
#: .\cookbook\forms.py:346
msgid ""
"Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods "
"only function with fulltext fields."
msgstr ""
"Поля для полнотекстового поиска. Примечание: методы поиска «web», «phrase» "
"и «raw» работают только с полнотекстовыми полями."
#: .\cookbook\forms.py:350
msgid "Search Method"
@@ -208,38 +218,40 @@ msgstr "Способ поиска"
#: .\cookbook\forms.py:350
msgid "Fuzzy Lookups"
msgstr ""
msgstr "Нечёткое сопоставление"
#: .\cookbook\forms.py:350
msgid "Ignore Accent"
msgstr ""
msgstr "Игнорировать акценты"
#: .\cookbook\forms.py:350
msgid "Partial Match"
msgstr ""
msgstr "Частичное совпадение"
#: .\cookbook\forms.py:350
msgid "Starts With"
msgstr ""
msgstr "Начинается с"
#: .\cookbook\forms.py:351
msgid "Fuzzy Search"
msgstr ""
msgstr "Неточный поиск"
#: .\cookbook\forms.py:351
msgid "Full Text"
msgstr ""
msgstr "Полный текст"
#: .\cookbook\helper\AllAuthCustomAdapter.py:41
msgid ""
"In order to prevent spam, the requested email was not send. Please wait a "
"few minutes and try again."
msgstr ""
"Во избежание спама запрошенное электронное письмо не было отправлено. "
"Подождите несколько минут и попробуйте снова."
#: .\cookbook\helper\permission_helper.py:164
#: .\cookbook\helper\permission_helper.py:187 .\cookbook\views\views.py:117
msgid "You are not logged in and therefore cannot view this page!"
msgstr ""
msgstr "Вы не вошли в систему и поэтому не можете просматривать эту страницу!"
#: .\cookbook\helper\permission_helper.py:168
#: .\cookbook\helper\permission_helper.py:174
@@ -252,7 +264,7 @@ msgstr ""
#: .\cookbook\helper\permission_helper.py:341 .\cookbook\views\data.py:35
#: .\cookbook\views\views.py:127 .\cookbook\views\views.py:131
msgid "You do not have the required permissions to view this page!"
msgstr ""
msgstr "У вас нет необходимых разрешений для просмотра этой страницы!"
#: .\cookbook\helper\permission_helper.py:192
#: .\cookbook\helper\permission_helper.py:215
@@ -260,102 +272,108 @@ msgstr ""
#: .\cookbook\helper\permission_helper.py:252
msgid "You cannot interact with this object as it is not owned by you!"
msgstr ""
"Вы не можете взаимодействовать с этим объектом, так как он не принадлежит "
"вам!"
#: .\cookbook\helper\permission_helper.py:402
msgid "You have reached the maximum number of recipes for your space."
msgstr ""
msgstr "Вы достигли максимального количества рецептов для вашего пространства."
#: .\cookbook\helper\permission_helper.py:414
msgid "You have more users than allowed in your space."
msgstr ""
msgstr "У вас больше пользователей, чем разрешено в вашем пространстве."
#: .\cookbook\helper\recipe_url_import.py:310
msgid "reverse rotation"
msgstr ""
msgstr "обратное вращение"
#: .\cookbook\helper\recipe_url_import.py:311
msgid "careful rotation"
msgstr ""
msgstr "осторожное вращение"
#: .\cookbook\helper\recipe_url_import.py:312
msgid "knead"
msgstr ""
msgstr "замесить"
#: .\cookbook\helper\recipe_url_import.py:313
msgid "thicken"
msgstr ""
msgstr "загустить"
#: .\cookbook\helper\recipe_url_import.py:314
msgid "warm up"
msgstr ""
msgstr "разогреть"
#: .\cookbook\helper\recipe_url_import.py:315
msgid "ferment"
msgstr ""
msgstr "ферментировать"
#: .\cookbook\helper\recipe_url_import.py:316
msgid "sous-vide"
msgstr ""
msgstr "су-вид"
#: .\cookbook\helper\shopping_helper.py:150
msgid "You must supply a servings size"
msgstr ""
msgstr "Вы должны указать размер порции"
#: .\cookbook\helper\template_helper.py:95
#: .\cookbook\helper\template_helper.py:97
msgid "Could not parse template code."
msgstr ""
msgstr "Не удалось разобрать код шаблона."
#: .\cookbook\integration\copymethat.py:44
#: .\cookbook\integration\melarecipes.py:37
msgid "Favorite"
msgstr ""
msgstr "Избранное"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "Я это сделал"
#: .\cookbook\integration\integration.py:209
msgid ""
"Importer expected a .zip file. Did you choose the correct importer type for "
"your data ?"
msgstr ""
"Импортер требует файл .zip. Вы выбрали правильный тип импортера для ваших "
"данных?"
#: .\cookbook\integration\integration.py:212
msgid ""
"An unexpected error occurred during the import. Please make sure you have "
"uploaded a valid file."
msgstr ""
"Во время импорта произошла непредвиденная ошибка. Пожалуйста, убедитесь, что "
"вы загрузили корректный файл."
#: .\cookbook\integration\integration.py:217
msgid "The following recipes were ignored because they already existed:"
msgstr ""
msgstr "Следующие рецепты были проигнорированы, так как уже существуют:"
#: .\cookbook\integration\integration.py:221
#, python-format
msgid "Imported %s recipes."
msgstr ""
msgstr "Импортировано %s рецептов."
#: .\cookbook\integration\openeats.py:28
msgid "Recipe source:"
msgstr ""
msgstr "Источник рецепта:"
#: .\cookbook\integration\paprika.py:49
msgid "Notes"
msgstr ""
msgstr "Заметки"
#: .\cookbook\integration\paprika.py:52
msgid "Nutritional Information"
msgstr ""
msgstr "Пищевая ценность"
#: .\cookbook\integration\paprika.py:56
msgid "Source"
msgstr ""
msgstr "Источник"
#: .\cookbook\integration\recettetek.py:54
#: .\cookbook\integration\recipekeeper.py:70
msgid "Imported from"
msgstr ""
msgstr "Импортировано из"
#: .\cookbook\integration\saffron.py:23
#, fuzzy
@@ -364,65 +382,67 @@ msgstr "Порции"
#: .\cookbook\integration\saffron.py:25
msgid "Waiting time"
msgstr ""
msgstr "Время ожидания"
#: .\cookbook\integration\saffron.py:27
msgid "Preparation Time"
msgstr ""
msgstr "Время подготовки"
#: .\cookbook\integration\saffron.py:29 .\cookbook\templates\index.html:7
msgid "Cookbook"
msgstr ""
msgstr "Книга рецептов"
#: .\cookbook\integration\saffron.py:31
msgid "Section"
msgstr ""
msgstr "Раздел"
#: .\cookbook\management\commands\fix_duplicate_properties.py:15
msgid "Fixes foods with "
msgstr ""
msgstr "Исправляет продукты с "
#: .\cookbook\management\commands\rebuildindex.py:14
msgid "Rebuilds full text search index on Recipe"
msgstr ""
msgstr "Перестраивает полнотекстовый индекс поиска для рецептов"
#: .\cookbook\management\commands\rebuildindex.py:18
msgid "Only Postgresql databases use full text search, no index to rebuild"
msgstr ""
"Полнотекстовый поиск используется только в базах данных Postgresql, индекс "
"перестраивать не нужно"
#: .\cookbook\management\commands\rebuildindex.py:29
msgid "Recipe index rebuild complete."
msgstr ""
msgstr "Перестройка индекса рецептов завершена."
#: .\cookbook\management\commands\rebuildindex.py:31
msgid "Recipe index rebuild failed."
msgstr ""
msgstr "Перестройка индекса рецептов не удалась."
#: .\cookbook\migrations\0047_auto_20200602_1133.py:14
msgid "Breakfast"
msgstr ""
msgstr "Завтрак"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:19
msgid "Lunch"
msgstr ""
msgstr "Обед"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:24
msgid "Dinner"
msgstr ""
msgstr "Ужин"
#: .\cookbook\migrations\0047_auto_20200602_1133.py:29 .\cookbook\models.py:919
msgid "Other"
msgstr ""
msgstr "Другое"
#: .\cookbook\migrations\0190_auto_20230525_1506.py:17
msgid "Fat"
msgstr ""
msgstr "Толстый"
#: .\cookbook\migrations\0190_auto_20230525_1506.py:17
#: .\cookbook\migrations\0190_auto_20230525_1506.py:18
#: .\cookbook\migrations\0190_auto_20230525_1506.py:19
msgid "g"
msgstr ""
msgstr "г"
#: .\cookbook\migrations\0190_auto_20230525_1506.py:18
msgid "Carbohydrates"

View File

@@ -19,7 +19,7 @@ server {
# pass requests for dynamic content to gunicorn
location / {
proxy_set_header Host $http_host;
proxy_pass http://web_recipes:8080;
proxy_pass http://localhost:8080;
error_page 502 /errors/http502.html;
}

View File

@@ -1,6 +1,6 @@
<template>
<v-dialog height="70vh" activator="parent" v-model="dialog">
<v-dialog max-width="1200px" activator="parent" v-model="dialog">
<v-card>
<v-closable-card-title v-model="dialog" :title="$t('Help')" icon="fa-solid fa-question">
<template #content>
@@ -13,68 +13,7 @@
</v-closable-card-title>
<v-divider></v-divider>
<v-card-text class="pa-0">
<v-layout style="height: 100%">
<v-navigation-drawer style="height: calc(100% + 0px)" v-model="drawer">
<v-list>
<v-list-item>
<v-text-field density="compact" variant="outlined" class="pt-2 pb-2" :label="$t('Search')" hide-details clearable></v-text-field>
</v-list-item>
<v-divider></v-divider>
<v-list-item link title="Start" @click="window = 'start'"></v-list-item>
<v-list-item link title="Space" @click="window = 'space'"></v-list-item>
</v-list>
</v-navigation-drawer>
<v-main>
<v-container>
<v-window v-model="window">
<v-window-item value="start">
<h2>Welcome to Tandoor 2</h2>
<p class="mt-3">Tandoor is one of the most most powerful recipe management suits available. It has constantly been improved since its first
version in 2018.
This knowledgebase explains all important features and concepts. Explore it to find out how Tandoor can help you improve your daily cooking
routine or search
for specific features to help you understand them.</p>
<p class="mt-3">Some of the most important concepts are Spaces, Recipes, Foods and Units.</p>
<v-alert class="mt-3" border="start" variant="tonal" color="success">
<v-alert-title>Did you know?</v-alert-title>
Tandoor is Open Source and available to anyone for free to host on their own server. Thousands of hours have been spend
making Tandoor what it is today. You can help make Tandoor even better by contributing or helping financing the effort.
<br/>
<v-btn class="mt-2" href="https://docs.tandoor.dev/contribute/contribute/" target="_blank" prepend-icon="fa-solid fa-code-branch">
Contribute
</v-btn>
<v-btn class="mt-2 ms-2" href="https://github.com/sponsors/vabene1111" target="_blank" prepend-icon="fa-solid fa-dollar-sign">Sponsor
</v-btn>
</v-alert>
</v-window-item>
<v-window-item value="space">
<p class="mt-3">All your data is stored in a Space where you can invite other people to collaborate on your recipe database. Typcially the members of a space
belong to one family/household/organization.</p>
<p class="mt-3">While everyone can access all recipes by default, Books, Shopping Lists and Mealplans are not shared by default. You can share them with other members of your space
using the settings.
</p>
<p class="mt-3">You can create and be a member of multiple spaces. Switch between them freely using the navigation or space settings. Depending
on the permission configured by the space owner you might not have access to all features of a space.</p>
<p class="mt-3"></p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-database" class="me-2" :to="{name: 'UserSpaceSettings'}">{{ $t('YourSpaces') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$settings" class="me-2" :to="{name: 'SpaceSettings'}">{{ $t('SpaceSettings') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-users" class="me-2" :to="{name: 'SpaceMemberSettings'}">{{ $t('Invites') }}</v-btn>
</v-window-item>
</v-window>
</v-container>
</v-main>
</v-layout>
<help-view v-model="drawer"></help-view>
</v-card-text>
</v-card>
</v-dialog>
@@ -85,9 +24,10 @@
import VClosableCardTitle from "@/components/dialogs/VClosableCardTitle.vue";
import {ref} from "vue";
import HelpView from "@/components/display/HelpView.vue";
const dialog = ref(false)
const window = ref('start')
const drawer = ref(true)
</script>

View File

@@ -0,0 +1,349 @@
<template>
<v-layout style="height: 70vh">
<v-navigation-drawer style="height: calc(100% + 0px)" v-model="drawer">
<v-list>
<!-- <v-list-item>-->
<!-- <v-text-field density="compact" variant="outlined" class="pt-2 pb-2" :label="$t('Search')" hide-details clearable></v-text-field>-->
<!-- </v-list-item>-->
<!-- <v-divider></v-divider>-->
<v-list-item link title="Start" @click="window = 'start'" prepend-icon="fa-solid fa-house"></v-list-item>
<v-list-item link title="Space" @click="window = 'space'" prepend-icon="fa-solid fa-database"></v-list-item>
<v-list-item link :title="$t('Recipes')" @click="window = 'recipes'" prepend-icon="$recipes"></v-list-item>
<v-list-item link :title="$t('Import')" @click="window = 'import'" prepend-icon="$import"></v-list-item>
<v-list-item link :title="$t('Unit')" @click="window = 'unit'" prepend-icon="fa-solid fa-scale-balanced"></v-list-item>
<v-list-item link :title="$t('Food')" @click="window = 'food'" prepend-icon="fa-solid fa-carrot"></v-list-item>
<v-list-item link :title="$t('Keyword')" @click="window = 'keyword'" prepend-icon="fa-solid fa-tags"></v-list-item>
<v-list-item link title="Recipe Structure" @click="window = 'recipe_structure'" prepend-icon="fa-solid fa-diagram-project"></v-list-item>
<v-list-item link :title="$t('Properties')" @click="window = 'properties'" prepend-icon="fa-solid fa-database"></v-list-item>
<v-list-item link :title="$t('Search')" @click="window = 'recipe_search'" prepend-icon="$search"></v-list-item>
<v-list-item link :title="$t('SavedSearch')" @click="window = 'search_filter'" prepend-icon="fa-solid fa-sd-card"></v-list-item>
<v-list-item link :title="$t('Books')" @click="window = 'books'" prepend-icon="$books"></v-list-item>
<v-list-item link :title="$t('Shopping')" @click="window = 'shopping'" prepend-icon="$shopping"></v-list-item>
<v-list-item link :title="$t('Meal_Plan')" @click="window = 'meal_plan'" prepend-icon="$mealplan"></v-list-item>
</v-list>
</v-navigation-drawer>
<v-main>
<v-container>
<v-window v-model="window">
<v-window-item value="start">
<h2>Welcome to Tandoor 2</h2>
<p class="mt-3">Tandoor is one of the most most powerful recipe management suits available. It has constantly been improved since its first
version in 2018.
This knowledgebase explains all important features and concepts. Explore it to find out how Tandoor can help you improve your daily cooking
routine or search
for specific features to help you understand them.</p>
<v-btn class="mt-2" color="primary" href="https://tandoor.dev" target="_blank" prepend-icon="fa-solid fa-globe">
Website
</v-btn>
<v-btn class="mt-2 ms-2" color="info" href="https://github.com/TandoorRecipes/recipes" target="_blank" prepend-icon="fa-solid fa-code-branch">GitHub
</v-btn>
<v-alert class="mt-3" border="start" variant="tonal" color="success">
<v-alert-title>Did you know?</v-alert-title>
Tandoor is Open Source and available to anyone for free to host on their own server. Thousands of hours have been spend
making Tandoor what it is today. You can help make Tandoor even better by contributing or helping financing the effort.
<br/>
<v-btn class="mt-2" color="secondary" href="https://docs.tandoor.dev/contribute/contribute/" target="_blank" prepend-icon="fa-solid fa-code-branch">
Contribute
</v-btn>
<v-btn class="mt-2 ms-2" color="success" href="https://github.com/sponsors/vabene1111" target="_blank" prepend-icon="fa-solid fa-dollar-sign">Sponsor
</v-btn>
</v-alert>
</v-window-item>
<v-window-item value="space">
<p class="mt-3">All your data is stored in a Space where you can invite other people to collaborate on your recipe database. Typcially the members of a space
belong to one family/household/organization.</p>
<p class="mt-3">While everyone can access all recipes by default, Books, Shopping Lists and Mealplans are not shared by default. You can share them with other
members of your space
using the settings.
</p>
<p class="mt-3">You can create and be a member of multiple spaces. Switch between them freely using the navigation or space settings. Depending
on the permission configured by the space owner you might not have access to all features of a space.</p>
<p class="mt-3"></p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-database" class="me-2" :to="{name: 'UserSpaceSettings'}">{{ $t('YourSpaces') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$settings" class="me-2" :to="{name: 'SpaceSettings'}">{{ $t('SpaceSettings') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-users" class="me-2" :to="{name: 'SpaceMemberSettings'}">{{ $t('Invites') }}</v-btn>
</v-window-item>
<v-window-item value="recipes">
<p class="mt-3">Recipes are the foundation of your Tandoor space. A Recipe has one or more steps that contain ingredients, instructions and other information.
Ingredients in turn consist of an amount, a unit and a food, allowing recipes to be scaled, nutrition's to be calculated and shopping to be organized.
</p>
<p class="mt-3">Besides manually creating them you can also import them from various different places.
</p>
<p class="mt-3">Recipes, by default, are visible to all members of your space. Setting them to private means only you can see it. After setting it to private you
can manually specify the people who should be able to view the recipe.
You can also create a share link for the recipe to share it with everyone that has access to the link.
</p>
<p class="mt-3"></p>
<v-btn color="primary" variant="tonal" prepend-icon="$create" class="me-2" :to="{name: 'ModelEditPage', params: {model: 'Recipe'}}">{{ $t('Create') }}</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$search" class="me-2" :to="{name: 'SearchPage'}">{{ $t('Search') }}</v-btn>
</v-window-item>
<v-window-item value="import">
<p class="mt-3">The Recipe importer is one of the most powerful features of Tandoor and allows you to quickly add recipes in multiple different ways.
</p>
<p class="mt-3">The easiest is to import from a URL. If that is not enough you can also import from an Image or PDF file using AI.
</p>
<p class="mt-3">If you already have an existing Recipe database in another format there is also a good chance Tandoor will have an
importer for that program.
</p>
<p class="mt-3"></p>
<v-btn color="primary" variant="tonal" prepend-icon="$import" class="me-2" :to="{name: 'RecipeImportPage'}">{{ $t('Import') }}</v-btn>
</v-window-item>
<v-window-item value="unit">
<p class="mt-3">Units allow you to measure how much of something you need in a recipe or on a shopping list.
They are also essential for the calculation of Properties.
</p>
<p class="mt-3">Setting a base unit allows you to name your Unit however you want (e.g. grams, g, G, gram) while allowing Tandoor
to automatically convert between the units in the same system (weight/volume, e.g. from g to kg or from cup to pint).
</p>
<p class="mt-3">Additionally you can use custom unit conversion to convert between volume and weight trough the specific density
of a food (e.g. 1 cup of flour = 120 g). These conversions are used to calculate the Properties for a Recipe
and might allow cosmetic display changes later.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-scale-balanced" class="me-2" :to="{name: 'ModelListPage', params: {model: 'Unit'}}">
{{ $t('Unit') }}
</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-exchange-alt" class="me-2" :to="{name: 'ModelListPage', params: {model: 'UnitConversion'}}">
{{ $t('Conversion') }}
</v-btn>
</v-window-item>
<v-window-item value="food">
<p class="mt-3">Foods have multiple uses in Tandoor. Their most important task is to be part of recipe ingredients together with an amount and
a unit.
</p>
<p class="mt-3">Using the Food editor you can also add properties to a food or link the food to another recipe or external URL.
</p>
<p class="mt-3">Foods are also used or created when adding entries to the shopping list.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-carrot" class="me-2" :to="{name: 'ModelListPage', params: {model: 'Food'}}">
{{ $t('Food') }}
</v-btn>
</v-window-item>
<v-window-item value="keyword">
<p class="mt-3">Keywords are a very flexible Tool to help you organize your recipe collection.
Keywords can quickly be created when editing a Recipe by just typing into the Keywords field or they can
be created trough the Keyword Editor.
</p>
<p class="mt-3">Typical keywords include meal types (breakfast, lunch, dinner, ...), couise (american, italian, ...) or diet (vegan, vegetarian, ..).
</p>
<p class="mt-3">Tip: Using Emojis in Keywords makes them easy to recognize.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-tags" class="me-2" :to="{name: 'ModelListPage', params: {model: 'Keyword'}}">
{{ $t('Keyword') }}
</v-btn>
</v-window-item>
<v-window-item value="recipe_structure">
<p class="mt-3">A Recipe consists of multiple Steps.
</p>
<p class="mt-3">Each Step has Ingreditens (which are at least a Food but typically consist of amount,
Unit and Food). A Step can also contain instuctions, times, files or link to another Recipe.
</p>
<p class="mt-3">Additionally a Recipe can have Properties, Comments, Keywords and more.
</p>
<!-- TODO diagram -->
</v-window-item>
<v-window-item value="properties">
<p class="mt-3">The Properties system allows you to add additional data to your Foods and Recipes in the respective editors.
Most commonly you would use this to add nutrition facts but the system can also be used to track prices,
dietary points or any other kind of property.
</p>
<p class="mt-3">You first need to create the Property Types that you need (e.g. Carbohydrates, Sugar, Price, Points, ..).
Setting the FDC ID for a Property Type allows Tandoor to connect your custom Property Type to a property in the FDC database.
You can then go to a Food, set its FDC ID and Tandoor can automatically pull the properties you want from the FDC database.
</p>
<p class="mt-3">When adding a Property to the Recipe it will just be statically displayed in the Recipe view.
Adding properties to a Foods will allow Tandoor to calculate the properties for all the Ingredients in a Recipe based
on the Foods and their respective Units and Amounts.
</p>
<p class="mt-3">Food Properties are entered based on a certain amount of food (often 100 g). Unit Conversions allow Tandoor to
calculate the property amount if a Food is given in a different unit (e.g. 1kg or 1 cup).
</p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-database" class="me-2 mt-2 mb-2" :to="{name: 'ModelListPage', params: {model: 'PropertyType'}}">
{{ $t('Property') }}
</v-btn>
<h3>Editor</h3>
<p class="mt-3">Adding Properties manually to every food can be cumbersome. To make it easier you can import the Community curated
Open Data Database. If that is not enough you can open the Property Editor trough the context menu on your recipe.
</p>
<p class="mt-3">Here you can view all Foods in a Recipe and their respective properties. You can also quickly assign FDC ID's to both
Foods and Property Types and import the data from the FDC Database.
</p>
<h3>View</h3>
<p class="mt-3">
Properties are shown below every recipe as soon as you setup your first Property Types.
A small warning triangle is shown if there are missing values for one of the Foods in the recipe.
</p>
<p class="mt-3">
Clicking on the warning triangle allows you to see the individual property amounts of each food and where Properties
or Unit Conversions are missing.
</p>
</v-window-item>
<v-window-item value="recipe_search">
<p class="mt-3">There are two ways to search for Recipes.
</p>
<p class="mt-3">The global quick search can be opened from any page in Tandoor by pressing the search icon in the top right corner.
Here you can quickly search trough your recipes and open them.
</p>
<p class="mt-3">
If you need a bit more fine tuning for your search you can open the advances search and search for all kinds of different things like keywords,
foods or ratings.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="$search" class="me-2" :to="{name: 'SearchPage', }">
{{ $t('Search') }}
</v-btn>
</v-window-item>
<v-window-item value="search_filter">
<p class="mt-3">Once you have performed an advanced search you can save the search filter to easily retrieve it later.
</p>
<p class="mt-3">
This is done by hitting the save button in the advanced search form. To load a search filter you simply select it from the
selection box and hit the load button.
</p>
<p class="mt-3">
You can use saved search filters to automatically create recipe books.
</p>
</v-window-item>
<v-window-item value="books">
<p class="mt-3">Books are a a way to structure and explore your recipe collection. They are similar to keywords but show you a bit more details when
looking trough them.
</p>
<p class="mt-3">After creating a new Book on the books page you can either add recipes manually or you can add a Saved Search Filter to automatically
load recipes into your book based on pre defined search criteria.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="$books" class="me-2" :to="{name: 'BooksPage', }">
{{ $t('Books') }}
</v-btn>
</v-window-item>
<v-window-item value="shopping">
<p class="mt-3">
You can add inidivitual Foods (including non Food items of course) or whole recipes to your shopping list.
By default only you can see the entries you make, by going to the settings you can share them with other users and they can share them with you.
</p>
<p class="mt-3">
You can assign Supermarket Categories to your Foods, either trough the Food Editor or directly by clicking on a Shopping List Entry, to automatically sort the list
according to the Category Order defined in the Supermarket.
</p>
<p class="mt-3">
Each line in the shopping list can contain multiple entries of the same Food.
By clicking on a line you can open a dialog that allows you to see the details and perform various actions.
</p>
<v-list>
<v-list-item>Postpone: Hide the entry from the shopping list for a certain time (specified in the settings)</v-list-item>
<v-list-item>Ignore: Check this Food of the list and do not add it again when adding a recipe to the shopping list</v-list-item>
<v-list-item>Edit: Open the Food's Editor</v-list-item>
<v-list-item>Delete all: Delete all entries associated with this line.</v-list-item>
</v-list>
<p class="mt-3">
The Shopping list automatically syncronizes when multiple people have it open so you can shop with multiple devices.
</p>
<p class="mt-3">
Trough the menu you can also configure which information you want to be displayed or how the list should be sorted.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="$shopping" class="me-2" :to="{name: 'ShoppingListPage', }">
{{ $t('Shopping') }}
</v-btn>
<v-btn color="primary" variant="tonal" prepend-icon="$settings" class="me-2" :to="{name: 'ShoppingSettings', }">
{{ $t('Settings') }}
</v-btn>
</v-window-item>
<v-window-item value="meal_plan">
<p class="mt-3">
To plan what you want to eat you can create a Meal Plan. Each Meal Plan consists of at least a title or a recipe, a date and a Meal Type.
Meal Plan entries a private by default and can either be shared individually or using a preset in the meal plan settings.
</p>
<p class="mt-3">
When selecting a Recipe in a Meal Plan you can automatically add its ingredients to the shopping list. You can also manually add more entries trough the
shopping tab in the Meal Plan editor. When deleting a Meal Plan all Shopping List Entries associated with that Meal Plan are deleted as well. When changing the
number of servings in a Meal Plan the Servings of the connected Recipe in the Shopping list are automatically changed as well.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="$mealplan" class="me-2 mt-2" :to="{name: 'MealPlanPage', }">
{{ $t('Meal_Plan') }}
</v-btn>
<h3 class="mt-3">{{ $t('Meal_Type') }}</h3>
<p class="mt-3">
Meal Types allow you to categorize the different Meal Plan Entries.
</p>
<p class="mt-3">
You can also define a time that is used for sorting and calendar integration.
</p>
<v-btn color="primary" variant="tonal" prepend-icon="fa-solid fa-utensils" class="me-2 mt-2" :to="{name: 'ModelListPage', params: {model: 'MealType'}}">
{{ $t('Meal_Type') }}
</v-btn>
</v-window-item>
</v-window>
</v-container>
</v-main>
</v-layout>
</template>
<script setup lang="ts">
import {ref} from "vue";
const drawer = defineModel()
const window = ref('start')
</script>
<style scoped>
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,84 +1,9 @@
<template>
<v-container>
<v-row>
<v-col>
<v-card>
<v-card-title class="text-h4">Welcome {{ useUserPreferenceStore().userSettings.user.displayName }}</v-card-title>
<v-card-text class="text-body-1">
<p>This page contains basic information to the most important features and concepts of Tandoor.</p>
<p> It is recommended to read at least the first few entries to get a feel of what Tandoor can do for you.</p>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row>
<v-col>
<v-expansion-panels>
<v-expansion-panel>
<v-expansion-panel-title>
<i :class="TUserSpace.icon" class="fa-fw me-2"></i> {{ $t('Space') }}
</v-expansion-panel-title>
<v-expansion-panel-text>
<p>All your data is stored in a space where you can invite other people to collaborate on your recipe database.</p>
<p class="mt-1">
Books, Shopping Lists and Mealplans are not shared by default. You can share them with specific other members of
your space using the settings.
</p>
<p class="mt-1">
You can create and be a member of multiple spaces. Switch between them freely using the navigation or space settings.
Depending on the permission configured by the space owner some features might not be available in all spaces.
</p>
<v-divider class="mt-2 mb-2"></v-divider>
<v-btn color="info" variant="tonal" prepend-icon="$settings" class="me-2" :to="{name: 'SpaceSettings'}">{{ $t('SpaceSettings') }}</v-btn>
<v-btn color="info" variant="tonal" prepend-icon="fa-solid fa-users" class="me-2" :to="{name: 'SpaceMemberSettings'}">{{ $t('Invites') }}</v-btn>
</v-expansion-panel-text>
</v-expansion-panel>
<v-expansion-panel>
<v-expansion-panel-title>
<i :class="TRecipe.icon" class="fa-fw me-2"></i> {{ $t('Recipes') }}
</v-expansion-panel-title>
<v-expansion-panel-text>
<p>Recipes are the foundation of your Tandoor space. A Recipe has one or more steps that contain
all ingredients, instructions and other information. Ingredients in turn consist of an amount, a unit and a food,
allowing recipes to be scaled, nutrition's to be calculated and shopping to be organized.</p>
<p class="mt-1">Besides manually creating them you can also
import them from various different places.</p>
<v-divider class="mt-2 mb-2"></v-divider>
<v-btn color="info" variant="tonal" prepend-icon="$create" class="me-2" :to="{ name: 'ModelEditPage', params: {model: 'recipe'} }">{{ $t('Create') }}
</v-btn>
<v-btn color="info" variant="tonal" prepend-icon="$import" class="me-2" :to="{ name: 'RecipeImportPage' }">{{ $t('Import') }}</v-btn>
</v-expansion-panel-text>
</v-expansion-panel>
<v-expansion-panel>
<v-expansion-panel-title>
<i :class="TUnit.icon" class="fa-fw me-2"></i> {{ $t('Units') }} & {{ $t('UnitConversion') }}
</v-expansion-panel-title>
<v-expansion-panel-text>
<p>Units allow you to measure how much of something you need in a recipe or on a shopping list. They are
also essential for the calculation of Properties. </p>
<p class="mt-1">Setting a base unit allows you to name your Unit however you want (e.g. grams, g, G, gram)
while allowing Tandoor to automatically convert between the units in the same system (weight/volume).
Additionally you can use custom unit conversion to convert between volume and weight trough the
specific density of a food (e.g. 1 cup of flour = 120 g). These conversions are used to calculate
the Properties for a Recipe and might allow cosmetic display changes later.</p>
<v-divider class="mt-2 mb-2"></v-divider>
<v-btn color="info" variant="tonal" prepend-icon="$create" class="me-2" :to="{ name: 'ModelEditPage', params: {model: 'unit'} }">{{ $t('Unit') }}
</v-btn>
<v-btn color="info" variant="tonal" prepend-icon="$create" class="me-2" :to="{ name: 'ModelEditPage', params: {model: 'unitconversion'} }">{{ $t('UnitConversion') }}</v-btn>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
<v-container height="70vh">
<v-row height="70vh" >
<v-col height="70vh">
<help-view height="70vh"></help-view>
</v-col>
</v-row>
@@ -88,9 +13,7 @@
<script setup lang="ts">
import {TKeyword, TRecipe, TUnit, TUserSpace} from "@/types/Models";
import {useUserPreferenceStore} from "../stores/UserPreferenceStore";
import HelpDialog from "@/components/dialogs/HelpDialog.vue";
import HelpView from "@/components/display/HelpView.vue";
</script>
<style scoped>

View File

@@ -16,6 +16,8 @@ export const plugin: TandoorPlugin = {
userNavigation: [
{component: VListItem, prependIcon: 'fa-solid fa-folder-tree', title: 'OpenData', to: {name: 'OpenDataPage', params: {}}},
],
disabled: true,
} as TandoorPlugin

View File

@@ -10,10 +10,14 @@ export type TandoorPlugin = {
navigationDrawer: any[],
bottomNavigation: any[],
userNavigation: any[],
disabled?: boolean
}
const pluginModules = import.meta.glob('@/plugins/*/plugin.ts', { eager: true })
export let TANDOOR_PLUGINS = [] as TandoorPlugin[]
Object.values(pluginModules).forEach(module => {
TANDOOR_PLUGINS.push(module.plugin)
if(!module.plugin.disabled){
TANDOOR_PLUGINS.push(module.plugin)
}
})