mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
add cookbook
This commit is contained in:
parent
35af888724
commit
3e34609fcf
5 changed files with 74 additions and 27 deletions
|
|
@ -10,7 +10,7 @@
|
|||
:autofocus="autofocus"
|
||||
@focus="isFocused = true"
|
||||
@blur="isFocused = false"
|
||||
>
|
||||
/>
|
||||
<kbd
|
||||
class="hidden md:inline-block kbd kbd-sm"
|
||||
:class="{ 'opacity-50': !isFocused }"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,29 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recipe } from "~/types/recipe";
|
||||
|
||||
defineProps<{ recipe: Recipe }>();
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
const { recipe } = defineProps<{ recipe: Recipe }>();
|
||||
|
||||
const cookbook = useLocalStorage<Recipe[]>("cookbook", []);
|
||||
|
||||
const likedRecipes = ref(new Set<string>());
|
||||
onMounted(() => {
|
||||
likedRecipes.value = new Set(cookbook.value.map((recipe) => recipe.id));
|
||||
console.log("cook", likedRecipes.value);
|
||||
});
|
||||
|
||||
const toggleLike = (recipeId: string) => {
|
||||
if (likedRecipes.value.has(recipeId)) {
|
||||
likedRecipes.value.delete(recipeId);
|
||||
cookbook.value = cookbook.value.filter((recipe) => recipe.id !== recipeId);
|
||||
} else {
|
||||
likedRecipes.value.add(recipeId);
|
||||
const recipeToAdd = recipe;
|
||||
if (recipeToAdd) {
|
||||
cookbook.value = [...cookbook.value, recipeToAdd];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const shareRecipe = async (recipe: Recipe) => {
|
||||
const url =
|
||||
|
|
@ -49,10 +71,23 @@ const shareRecipe = async (recipe: Recipe) => {
|
|||
<p class="prose prose-lg max-w-none w-full">
|
||||
{{ recipe.instructions }}
|
||||
</p>
|
||||
<button class="btn btn-accent mt-4" @click="shareRecipe(recipe)">
|
||||
<icon name="uil:share-alt" class="mr-2 w-6 h-6" />
|
||||
Share Recipe
|
||||
</button>
|
||||
<div class="flex gap-4 mt-4">
|
||||
<button class="btn btn-accent" @click="shareRecipe(recipe)">
|
||||
<icon name="uil:share-alt" class="mr-2 w-6 h-6" />
|
||||
Share Recipe
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-ghost"
|
||||
@click="toggleLike(recipe.id)"
|
||||
:class="{ 'text-red-500': likedRecipes.has(recipe.id) }"
|
||||
>
|
||||
<icon
|
||||
:name="likedRecipes.has(recipe.id) ? 'uil:heart' : 'uil:heart-alt'"
|
||||
class="w-6 h-6"
|
||||
/>
|
||||
Like
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { Recipe } from "~/types/recipe";
|
||||
|
||||
const cookbook = [] as Recipe[];
|
||||
import { useStorage } from "@vueuse/core";
|
||||
const cookbook = useStorage<Recipe[]>("cookbook", [], localStorage);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -16,7 +16,7 @@ const cookbook = [] as Recipe[];
|
|||
</div>
|
||||
<ul>
|
||||
<li v-for="recipe in cookbook" :key="recipe.id">
|
||||
<nuxt-link :to="`/recipes/${recipe.id}`">
|
||||
<nuxt-link :to="`/${recipe.id}`">
|
||||
<recipe-card
|
||||
:title="recipe.title"
|
||||
:picture-url="recipe.pictureUrl"
|
||||
|
|
|
|||
|
|
@ -11,20 +11,24 @@ import { publicProcedure, router } from "../trpc";
|
|||
const { apiUrl } = useRuntimeConfig();
|
||||
|
||||
export const recipeRouter = router({
|
||||
recipesByCategory: publicProcedure.input(z.string()).query(async ({ input }) => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(new URL(`filter.php?c=${input}`, apiUrl).href);
|
||||
recipesByCategory: publicProcedure
|
||||
.input(z.string())
|
||||
.query(async ({ input }) => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL(`filter.php?c=${input}`, apiUrl).href,
|
||||
);
|
||||
|
||||
const result = categoryRecipesResponseSchema.safeParse(data);
|
||||
const result = categoryRecipesResponseSchema.safeParse(data);
|
||||
|
||||
if (!result.success) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Recipes for category not found",
|
||||
});
|
||||
}
|
||||
if (!result.success) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Recipes for category not found",
|
||||
});
|
||||
}
|
||||
|
||||
return result.data.recipes;
|
||||
}),
|
||||
return result.data.recipes;
|
||||
}),
|
||||
|
||||
recipeGet: publicProcedure
|
||||
.input(
|
||||
|
|
@ -33,10 +37,12 @@ export const recipeRouter = router({
|
|||
required_error: "recipe id is required",
|
||||
invalid_type_error: "recipe id must be a number",
|
||||
})
|
||||
.positive("recipe id must be positive")
|
||||
.positive("recipe id must be positive"),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(new URL(`lookup.php?i=${input}`, apiUrl).href);
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL(`lookup.php?i=${input}`, apiUrl).href,
|
||||
);
|
||||
if (!data?.meals) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
|
|
@ -49,7 +55,9 @@ export const recipeRouter = router({
|
|||
}),
|
||||
|
||||
recipeRandom: publicProcedure.query(async () => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(new URL("random.php", apiUrl).toString());
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL("random.php", apiUrl).toString(),
|
||||
);
|
||||
if (!data?.meals) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
|
|
@ -64,10 +72,12 @@ export const recipeRouter = router({
|
|||
.input(
|
||||
z.string({
|
||||
required_error: "search query is required",
|
||||
})
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(new URL(`search.php?s=${input}`, apiUrl).href);
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL(`search.php?s=${input}`, apiUrl).href,
|
||||
);
|
||||
if (!data?.meals) {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -76,7 +86,9 @@ export const recipeRouter = router({
|
|||
}),
|
||||
|
||||
listCategories: publicProcedure.query(async () => {
|
||||
const response = await $fetch<CategoriesResponse>(new URL("categories.php", apiUrl).href);
|
||||
const response = await $fetch<CategoriesResponse>(
|
||||
new URL("categories.php", apiUrl).href,
|
||||
);
|
||||
|
||||
const result = categoriesResponseSchema.safeParse(response);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { initTRPC , TRPCError } from "@trpc/server";
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import type { Context } from "~/server/trpc/context";
|
||||
// import { authMiddleware } from "~/server/trpc/middleware";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue