Merge branch 'develop'

This commit is contained in:
vabene1111
2025-09-25 07:39:38 +02:00
8 changed files with 44 additions and 19 deletions

View File

@@ -30,9 +30,11 @@
![Preview](docs/preview.png)
## Core Features
- 🥗 **Manage your recipes** - Manage your ever growing recipe collection
- 📆 **Plan** - multiple meals for each day
- 🛒 **Shopping lists** - via the meal plan or straight from recipes
- 🪄 **use AI** to recognize images, sort recipe steps, find nutrition facts and more
- 📚 **Cookbooks** - collect recipes into books
- 👪 **Share and collaborate** on recipes with friends and family
@@ -62,12 +64,13 @@ a public page.
Documentation can be found [here](https://docs.tandoor.dev/).
## Support our work
## ❤️ Support our work ❤️
Tandoor is developed by volunteers in their free time just because its fun. That said earning
some money with the project allows us to spend more time on it and thus make improvements we otherwise couldn't.
Because of that there are several ways you can support us
- **GitHub Sponsors** You can sponsor contributors of this project on GitHub: [vabene1111](https://github.com/sponsors/vabene1111)
- **Patron** You can sponsor contributors of this project on Patron: [vabene111](https://www.patreon.com/cw/vabene1111)
- **Host at Hetzner** We have been very happy customers of Hetzner for multiple years for all of our projects. If you want to get into self-hosting or are tired of the expensive big providers, their cloud servers are a great place to get started. When you sign up via our [referral link](https://hetzner.cloud/?ref=ISdlrLmr9kGj) you will get 20€ worth of cloud credits and we get a small kickback too.
- **Let us host for you** We are offering a [hosted version](https://app.tandoor.dev) where all profits support us and the development of tandoor (currently only available in germany).

View File

@@ -0,0 +1,26 @@
# Generated by Django 5.2.6 on 2025-09-24 17:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0228_space_space_setup_completed'),
]
operations = [
migrations.AlterModelOptions(
name='ailog',
options={'ordering': ('-created_at',)},
),
migrations.AlterModelOptions(
name='aiprovider',
options={'ordering': ('id',)},
),
migrations.AlterField(
model_name='storage',
name='token',
field=models.CharField(blank=True, max_length=4098, null=True),
),
]

View File

@@ -592,7 +592,7 @@ class Storage(models.Model, PermissionModelMixin):
)
username = models.CharField(max_length=128, blank=True, null=True)
password = models.CharField(max_length=128, blank=True, null=True)
token = models.CharField(max_length=512, blank=True, null=True)
token = models.CharField(max_length=4098, blank=True, null=True)
url = models.URLField(blank=True, null=True)
path = models.CharField(blank=True, default='', max_length=256)
created_by = models.ForeignKey(User, on_delete=models.PROTECT)

View File

@@ -1,7 +1,7 @@
<template>
<v-card class="mt-1 d-print-none" v-if="useUserPreferenceStore().isAuthenticated" :loading="loading">
<v-card-text>
<v-textarea :label="$t('Comment')" rows="2" v-model="newCookLog.comment"></v-textarea>
<v-textarea :label="$t('Comment')" rows="2" v-model="newCookLog.comment" auto-grow></v-textarea>
<v-row dense>
<v-col cols="12" md="4">
<v-label>{{ $t('Rating') }}</v-label>

View File

@@ -98,10 +98,10 @@ const mergedIngredients = computed(() => {
const groupedIngredients = new Map<string, Ingredient>();
allIngredients.forEach(ingredient => {
if (!ingredient.food || !ingredient.unit) return;
if (!ingredient.food) return;
// Create a unique key for food-unit combination
const key = `${ingredient.food.id}-${ingredient.unit.id}`;
const key = `${ingredient.food.id}-${(ingredient.unit ? ingredient.unit.id : 'no_unit')}`;
if (groupedIngredients.has(key)) {
// If this food-unit combination already exists, sum the amounts

View File

@@ -2,7 +2,7 @@
<!-- TODO label is not showing for some reason, for now in placeholder -->
<v-label class="mt-2" v-if="props.label">{{ props.label }}</v-label>
<v-input :hint="props.hint" persistent-hint :label="props.label" :hide-details="props.hideDetails">
<v-input :hint="props.hint" persistent-hint :label="props.label" :hide-details="props.hideDetails" :disabled="props.disabled">
<template #prepend v-if="$slots.prepend">
<slot name="prepend"></slot>
</template>
@@ -37,6 +37,7 @@
:classes="{
dropdown: 'multiselect-dropdown z-3000',
containerActive: '',
containerDisabled: 'text-disabled'
}"
>
<template #option="{ option }" v-if="props.allowCreate">

View File

@@ -60,32 +60,27 @@
<v-label>{{ $t('Ingredients') }}</v-label>
<div v-if="!mobile">
<vue-draggable v-model="step.ingredients" handle=".drag-handle" :on-sort="sortIngredients" :empty-insert-threshold="25" group="ingredients">
<v-row v-for="(ingredient, index) in step.ingredients" :key="ingredient.id" class="d-flex" dense>
<v-row v-for="(ingredient, index) in step.ingredients" :key="ingredient.id" class="d-flex flex-nowrap" dense>
<v-col cols="12" class="pa-0 ma-0 text-center text-disabled" v-if="ingredient.originalText">
<v-icon icon="$import" size="x-small"></v-icon>
{{ ingredient.originalText }}
</v-col>
<div class="flex-col flex-grow-0 ma-1" style="width: 15vw" v-if="!ingredient.isHeader">
<v-input hide-details>
<template #prepend>
<v-icon icon="$dragHandle" class="drag-handle cursor-grab mt-2" v-if="ingredient.noAmount" density="compact"></v-icon>
</template>
</v-input>
<div class="flex-col flex-grow-0 ma-1" style="min-width: 15%" v-if="!ingredient.isHeader">
<v-text-field :id="`id_input_amount_${step.id}_${index}`" :label="$t('Amount')" type="number" v-model="ingredient.amount" density="compact"
hide-details v-if="!ingredient.noAmount">
hide-details :disabled="ingredient.noAmount">
<template #prepend>
<v-icon icon="$dragHandle" class="drag-handle cursor-grab"></v-icon>
</template>
</v-text-field>
</div>
<div class="flex-col flex-grow-0 ma-1" style="min-width: 20vw" v-if="!ingredient.isHeader ">
<model-select model="Unit" v-model="ingredient.unit" density="compact" allow-create hide-details v-if="!ingredient.noAmount"></model-select>
<div class="flex-col flex-grow-0 ma-1" style="min-width: 15%" v-if="!ingredient.isHeader ">
<model-select model="Unit" v-model="ingredient.unit" density="compact" allow-create hide-details :disabled="ingredient.noAmount"></model-select>
</div>
<div class="flex-col flex-grow-0 ma-1" style="min-width: 20vw" v-if="!ingredient.isHeader">
<div class="flex-col flex-grow-1 ma-1" style="min-width: 15%" v-if="!ingredient.isHeader">
<model-select model="Food" v-model="ingredient.food" density="compact" allow-create hide-details></model-select>
</div>
<div class="flex-col flex-grow-1 ma-1" @keydown.tab="event => handleIngredientNoteTab(event, index)">
<div class="flex-col ma-1" style="min-width: 15%" :class="{'flex-grow-1': ingredient.isHeader, 'flex-grow-0': !ingredient.isHeader}" @keydown.tab="event => handleIngredientNoteTab(event, index)">
<v-text-field :label="(ingredient.isHeader) ? $t('Headline') : $t('Note')" v-model="ingredient.note" density="compact" hide-details>
<template #prepend v-if="ingredient.isHeader">
<v-icon icon="$dragHandle" class="drag-handle cursor-grab"></v-icon>

View File

@@ -95,7 +95,7 @@
</v-number-input>
<v-btn variant="outlined" color="create" block v-if="p.propertyAmount == null" @click="p.propertyAmount = 0">
<v-btn variant="outlined" color="create" block v-if="p.propertyAmount == null" @click="p.propertyAmount = 0; updateFood(ingredient)">
<v-icon icon="$create"></v-icon>
</v-btn>
</td>