diff --git a/frontend/pages/g/[groupSlug]/r/create/new.vue b/frontend/pages/g/[groupSlug]/r/create/new.vue index 29948d304..2c9f50f8f 100644 --- a/frontend/pages/g/[groupSlug]/r/create/new.vue +++ b/frontend/pages/g/[groupSlug]/r/create/new.vue @@ -46,6 +46,7 @@ import type { AxiosResponse } from "axios"; import { useUserApi } from "~/composables/api"; import { validators } from "~/composables/use-validators"; import type { VForm } from "~/types/auto-forms"; +import { alert } from "~/composables/use-toast"; export default defineNuxtComponent({ setup() { @@ -59,6 +60,7 @@ export default defineNuxtComponent({ const api = useUserApi(); const router = useRouter(); + const i18n = useI18n(); function handleResponse(response: AxiosResponse | null, edit = false) { if (response?.status !== 201) { @@ -71,11 +73,25 @@ export default defineNuxtComponent({ const newRecipeName = ref(""); const domCreateByName = ref(null); + function createRecipeSlug(str: string): string { + return str + .toLowerCase() + .normalize("NFD") + .replace(/\p{Diacritic}/gu, "") + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, "") + .replace(/-+/g, "-"); + } async function createByName(name: string) { if (!domCreateByName.value?.validate() || name === "") { return; } + const recipeSlug = createRecipeSlug(name); + if (!recipeSlug) { + alert.error(i18n.t("recipe.recipe-creation-failed") as string); + return; + } const { response } = await api.recipes.createOne({ name }); handleResponse(response as any, true); } diff --git a/mealie/schema/recipe/recipe.py b/mealie/schema/recipe/recipe.py index ffc62d112..9670023ef 100644 --- a/mealie/schema/recipe/recipe.py +++ b/mealie/schema/recipe/recipe.py @@ -47,6 +47,8 @@ def create_recipe_slug(name: str, max_length: int = 250) -> str: A truncated slug string """ generated_slug = slugify(name) + if not generated_slug: + generated_slug = "untitled" if len(generated_slug) > max_length: generated_slug = generated_slug[:max_length] return generated_slug