diff --git a/frontend/components/Domain/Cookbook/CookbookPage.vue b/frontend/components/Domain/Cookbook/CookbookPage.vue new file mode 100644 index 000000000000..2afb33e7722a --- /dev/null +++ b/frontend/components/Domain/Cookbook/CookbookPage.vue @@ -0,0 +1,74 @@ + + + diff --git a/frontend/components/Domain/Recipe/RecipeCard.vue b/frontend/components/Domain/Recipe/RecipeCard.vue index 09ae988604e8..e13bd40d4f21 100644 --- a/frontend/components/Domain/Recipe/RecipeCard.vue +++ b/frontend/components/Domain/Recipe/RecipeCard.vue @@ -4,7 +4,7 @@ @@ -39,7 +39,10 @@ + + { return $auth.loggedIn; }); + const recipeRoute = computed(() => { + return loggedIn.value ? `/recipe/${props.slug}` : `/explore/recipes/${props.groupSlug}/${props.slug}`; + }); + return { loggedIn, + recipeRoute, }; }, }); diff --git a/frontend/components/Domain/Recipe/RecipeCardMobile.vue b/frontend/components/Domain/Recipe/RecipeCardMobile.vue index 507a19696030..57e7be9b3a73 100644 --- a/frontend/components/Domain/Recipe/RecipeCardMobile.vue +++ b/frontend/components/Domain/Recipe/RecipeCardMobile.vue @@ -4,7 +4,7 @@ :ripple="false" :class="isFlat ? 'mx-auto flat' : 'mx-auto'" hover - :to="$listeners.selected ? undefined : `/recipe/${slug}`" + :to="$listeners.selected ? undefined : recipeRoute" @click="$emit('selected')" > @@ -40,7 +40,7 @@ + + + { return $auth.loggedIn; }); + const recipeRoute = computed(() => { + return loggedIn.value ? `/recipe/${props.slug}` : `/explore/recipes/${props.groupSlug}/${props.slug}`; + }); + return { loggedIn, + recipeRoute, }; }, }); diff --git a/frontend/components/Domain/Recipe/RecipeCardSection.vue b/frontend/components/Domain/Recipe/RecipeCardSection.vue index 30211b7f1d2d..5442ecd2e23f 100644 --- a/frontend/components/Domain/Recipe/RecipeCardSection.vue +++ b/frontend/components/Domain/Recipe/RecipeCardSection.vue @@ -76,6 +76,7 @@ Recipe[], default: () => [], @@ -184,7 +190,10 @@ export default defineComponent({ shuffle: "shuffle", }; - const { $globals, $vuetify } = useContext(); + const { $auth, $globals, $vuetify } = useContext(); + const loggedIn = computed(() => { + return $auth.loggedIn; + }); const useMobileCards = computed(() => { return $vuetify.breakpoint.smAndDown || preferences.value.useMobileCards; }); @@ -202,7 +211,7 @@ export default defineComponent({ if (props.recipes.length > 0) { const recipe = props.recipes[Math.floor(Math.random() * props.recipes.length)]; if (recipe.slug !== undefined) { - router.push(`/recipe/${recipe.slug}`); + router.push(loggedIn.value ? `/recipe/${recipe.slug}` : `/explore/recipes/${props.groupSlug}/${recipe.slug}`); } } } @@ -213,7 +222,7 @@ export default defineComponent({ const ready = ref(false); const loading = ref(false); - const { fetchMore } = useLazyRecipes(); + const { fetchMore } = useLazyRecipes(loggedIn.value ? null : props.groupSlug); const queryFilter = computed(() => { const orderBy = props.query?.orderBy || preferences.value.orderBy; diff --git a/frontend/components/Domain/Recipe/RecipeChips.vue b/frontend/components/Domain/Recipe/RecipeChips.vue index b3812c78d87e..1c8c46306bd2 100644 --- a/frontend/components/Domain/Recipe/RecipeChips.vue +++ b/frontend/components/Domain/Recipe/RecipeChips.vue @@ -9,7 +9,7 @@ color="accent" :small="small" dark - :to="`/?${urlPrefix}=${category.id}`" + :to=" loggedIn ? `/?${urlPrefix}=${category.id}` : undefined" > {{ truncateText(category.name) }} @@ -17,7 +17,7 @@ + + diff --git a/frontend/components/Layout/DefaultLayout.vue b/frontend/components/Layout/DefaultLayout.vue new file mode 100644 index 000000000000..b0071bc95f12 --- /dev/null +++ b/frontend/components/Layout/DefaultLayout.vue @@ -0,0 +1,216 @@ + + + diff --git a/frontend/components/Layout/AppFooter.vue b/frontend/components/Layout/LayoutParts/AppFooter.vue similarity index 97% rename from frontend/components/Layout/AppFooter.vue rename to frontend/components/Layout/LayoutParts/AppFooter.vue index 510a47431cc6..3042076a9193 100644 --- a/frontend/components/Layout/AppFooter.vue +++ b/frontend/components/Layout/LayoutParts/AppFooter.vue @@ -12,7 +12,7 @@ - + - diff --git a/frontend/components/Layout/AppHeader.vue b/frontend/components/Layout/LayoutParts/AppHeader.vue similarity index 83% rename from frontend/components/Layout/AppHeader.vue rename to frontend/components/Layout/LayoutParts/AppHeader.vue index 1f5feb937862..5af4088d9c09 100644 --- a/frontend/components/Layout/AppHeader.vue +++ b/frontend/components/Layout/LayoutParts/AppHeader.vue @@ -1,14 +1,14 @@ \ No newline at end of file + diff --git a/frontend/layouts/blank.vue b/frontend/layouts/blank.vue index 10c5973e1c1c..c9bccf58291e 100644 --- a/frontend/layouts/blank.vue +++ b/frontend/layouts/blank.vue @@ -20,7 +20,7 @@ diff --git a/frontend/layouts/explore.vue b/frontend/layouts/explore.vue new file mode 100644 index 000000000000..6bc10eadd0a6 --- /dev/null +++ b/frontend/layouts/explore.vue @@ -0,0 +1,13 @@ + + + + diff --git a/frontend/lib/api/base/base-clients.ts b/frontend/lib/api/base/base-clients.ts index 265549cc74a4..d993216eb6d1 100644 --- a/frontend/lib/api/base/base-clients.ts +++ b/frontend/lib/api/base/base-clients.ts @@ -20,11 +20,10 @@ export abstract class BaseAPI { } } -export abstract class BaseCRUDAPI +export abstract class BaseCRUDAPIReadOnly extends BaseAPI - implements CrudAPIInterface -{ - abstract baseRoute: string; + implements CrudAPIInterface { + abstract baseRoute: (string); abstract itemRoute(itemId: string | number): string; async getAll(page = 1, perPage = -1, params = {} as Record) { @@ -32,13 +31,17 @@ export abstract class BaseCRUDAPI return await this.requests.get>(route(this.baseRoute, { page, perPage, ...params })); } - async createOne(payload: CreateType) { - return await this.requests.post(this.baseRoute, payload); - } - async getOne(itemId: string | number) { return await this.requests.get(this.itemRoute(itemId)); } +} + +export abstract class BaseCRUDAPI + extends BaseCRUDAPIReadOnly + implements CrudAPIInterface { + async createOne(payload: CreateType) { + return await this.requests.post(this.baseRoute, payload); + } async updateOne(itemId: string | number, payload: UpdateType) { return await this.requests.put(this.itemRoute(itemId), payload); diff --git a/frontend/lib/api/client-public.ts b/frontend/lib/api/client-public.ts index b613d616ffea..7745c3c54862 100644 --- a/frontend/lib/api/client-public.ts +++ b/frontend/lib/api/client-public.ts @@ -5,13 +5,20 @@ import { ApiRequestInstance } from "~/lib/api/types/non-generated"; export class PublicApi { public validators: ValidatorsApi; - public explore: ExploreApi; public shared: SharedApi; constructor(requests: ApiRequestInstance) { this.validators = new ValidatorsApi(requests); - this.explore = new ExploreApi(requests); this.shared = new SharedApi(requests); + } +} + +export class PublicExploreApi extends PublicApi { + public explore: ExploreApi; + + constructor(requests: ApiRequestInstance, groupSlug: string) { + super(requests); + this.explore = new ExploreApi(requests, groupSlug); Object.freeze(this); } diff --git a/frontend/lib/api/public/explore.ts b/frontend/lib/api/public/explore.ts index a750e42a16fa..51f7d71357e5 100644 --- a/frontend/lib/api/public/explore.ts +++ b/frontend/lib/api/public/explore.ts @@ -1,14 +1,25 @@ import { BaseAPI } from "../base/base-clients"; -import { Recipe } from "~/lib/api/types/recipe"; - -const prefix = "/api"; - -const routes = { - recipe: (groupSlug: string, recipeSlug: string) => `${prefix}/explore/recipes/${groupSlug}/${recipeSlug}`, -}; +import { ApiRequestInstance } from "~/lib/api/types/non-generated"; +import { PublicRecipeApi } from "./explore/recipes"; +import { PublicFoodsApi } from "./explore/foods"; +import { PublicCategoriesApi, PublicTagsApi, PublicToolsApi } from "./explore/organizers"; +import { PublicCookbooksApi } from "./explore/cookbooks"; export class ExploreApi extends BaseAPI { - async recipe(groupSlug: string, recipeSlug: string) { - return await this.requests.get(routes.recipe(groupSlug, recipeSlug)); + public recipes: PublicRecipeApi; + public cookbooks: PublicCookbooksApi; + public foods: PublicFoodsApi; + public categories: PublicCategoriesApi; + public tags: PublicTagsApi; + public tools: PublicToolsApi; + + constructor(requests: ApiRequestInstance, groupSlug: string) { + super(requests); + this.recipes = new PublicRecipeApi(requests, groupSlug); + this.cookbooks = new PublicCookbooksApi(requests, groupSlug); + this.foods = new PublicFoodsApi(requests, groupSlug); + this.categories = new PublicCategoriesApi(requests, groupSlug); + this.tags = new PublicTagsApi(requests, groupSlug); + this.tools = new PublicToolsApi(requests, groupSlug); } } diff --git a/frontend/lib/api/public/explore/cookbooks.ts b/frontend/lib/api/public/explore/cookbooks.ts new file mode 100644 index 000000000000..0cf184a1f14a --- /dev/null +++ b/frontend/lib/api/public/explore/cookbooks.ts @@ -0,0 +1,19 @@ +import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients"; +import { RecipeCookBook } from "~/lib/api/types/cookbook"; +import { ApiRequestInstance } from "~/lib/api/types/non-generated"; + +const prefix = "/api"; + +const routes = { + cookbooksGroupSlug: (groupSlug: string | number) => `${prefix}/explore/cookbooks/${groupSlug}`, + cookbooksGroupSlugCookbookId: (groupSlug: string | number, cookbookId: string | number) => `${prefix}/explore/cookbooks/${groupSlug}/${cookbookId}`, +}; + +export class PublicCookbooksApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.cookbooksGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.cookbooksGroupSlugCookbookId(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} diff --git a/frontend/lib/api/public/explore/foods.ts b/frontend/lib/api/public/explore/foods.ts new file mode 100644 index 000000000000..b2ebbe8c7627 --- /dev/null +++ b/frontend/lib/api/public/explore/foods.ts @@ -0,0 +1,19 @@ +import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients"; +import { IngredientFood } from "~/lib/api/types/recipe"; +import { ApiRequestInstance } from "~/lib/api/types/non-generated"; + +const prefix = "/api"; + +const routes = { + foodsGroupSlug: (groupSlug: string | number) => `${prefix}/explore/foods/${groupSlug}`, + foodsGroupSlugFoodId: (groupSlug: string | number, foodId: string | number) => `${prefix}/explore/foods/${groupSlug}/${foodId}`, +}; + +export class PublicFoodsApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.foodsGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.foodsGroupSlugFoodId(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} diff --git a/frontend/lib/api/public/explore/organizers.ts b/frontend/lib/api/public/explore/organizers.ts new file mode 100644 index 000000000000..26b4734f0665 --- /dev/null +++ b/frontend/lib/api/public/explore/organizers.ts @@ -0,0 +1,41 @@ +import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients"; +import { RecipeCategory, RecipeTag, RecipeTool } from "~/lib/api/types/recipe"; +import { ApiRequestInstance } from "~/lib/api/types/non-generated"; + +const prefix = "/api"; + +const routes = { + categoriesGroupSlug: (groupSlug: string | number) => `${prefix}/explore/organizers/${groupSlug}/categories`, + categoriesGroupSlugCategoryId: (groupSlug: string | number, categoryId: string | number) => `${prefix}/explore/organizers/${groupSlug}/categories/${categoryId}`, + tagsGroupSlug: (groupSlug: string | number) => `${prefix}/explore/organizers/${groupSlug}/tags`, + tagsGroupSlugTagId: (groupSlug: string | number, tagId: string | number) => `${prefix}/explore/organizers/${groupSlug}/tags/${tagId}`, + toolsGroupSlug: (groupSlug: string | number) => `${prefix}/explore/organizers/${groupSlug}/tools`, + toolsGroupSlugToolId: (groupSlug: string | number, toolId: string | number) => `${prefix}/explore/organizers/${groupSlug}/tools/${toolId}`, +}; + +export class PublicCategoriesApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.categoriesGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.categoriesGroupSlugCategoryId(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} + +export class PublicTagsApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.tagsGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.tagsGroupSlugTagId(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} + +export class PublicToolsApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.toolsGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.toolsGroupSlugToolId(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} diff --git a/frontend/lib/api/public/explore/recipes.ts b/frontend/lib/api/public/explore/recipes.ts new file mode 100644 index 000000000000..060ada6e03f2 --- /dev/null +++ b/frontend/lib/api/public/explore/recipes.ts @@ -0,0 +1,19 @@ +import { BaseCRUDAPIReadOnly } from "~/lib/api/base/base-clients"; +import { Recipe } from "~/lib/api/types/recipe"; +import { ApiRequestInstance } from "~/lib/api/types/non-generated"; + +const prefix = "/api"; + +const routes = { + recipesGroupSlug: (groupSlug: string | number) => `${prefix}/explore/recipes/${groupSlug}`, + recipesGroupSlugRecipeSlug: (groupSlug: string | number, recipeSlug: string | number) => `${prefix}/explore/recipes/${groupSlug}/${recipeSlug}`, +}; + +export class PublicRecipeApi extends BaseCRUDAPIReadOnly { + baseRoute = routes.recipesGroupSlug(this.groupSlug); + itemRoute = (itemId: string | number) => routes.recipesGroupSlugRecipeSlug(this.groupSlug, itemId); + + constructor(requests: ApiRequestInstance, private readonly groupSlug: string) { + super(requests); + } +} diff --git a/frontend/pages/cookbooks/_slug.vue b/frontend/pages/cookbooks/_slug.vue index ee32f9f5f512..9b768831bcd0 100644 --- a/frontend/pages/cookbooks/_slug.vue +++ b/frontend/pages/cookbooks/_slug.vue @@ -1,64 +1,12 @@ diff --git a/frontend/pages/explore/cookbooks/_groupSlug/_slug.vue b/frontend/pages/explore/cookbooks/_groupSlug/_slug.vue new file mode 100644 index 000000000000..35387761892c --- /dev/null +++ b/frontend/pages/explore/cookbooks/_groupSlug/_slug.vue @@ -0,0 +1,23 @@ + + + diff --git a/frontend/pages/explore/recipes/_groupSlug/_slug.vue b/frontend/pages/explore/recipes/_groupSlug/_recipeSlug.vue similarity index 75% rename from frontend/pages/explore/recipes/_groupSlug/_slug.vue rename to frontend/pages/explore/recipes/_groupSlug/_recipeSlug.vue index 70f197a9e073..492a3422fdde 100644 --- a/frontend/pages/explore/recipes/_groupSlug/_slug.vue +++ b/frontend/pages/explore/recipes/_groupSlug/_recipeSlug.vue @@ -1,7 +1,7 @@ @@ -9,24 +9,24 @@ diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 78bae22a4bdc..676355a0c15e 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -1,481 +1,40 @@ - - diff --git a/frontend/pages/user/profile/index.vue b/frontend/pages/user/profile/index.vue index 603b4df911a0..316114ff94ec 100644 --- a/frontend/pages/user/profile/index.vue +++ b/frontend/pages/user/profile/index.vue @@ -16,18 +16,29 @@ {{ $t('profile.get-invite-link') }} + + + {{ $globals.icons.shareVariant }} + + {{ $t('profile.get-public-link') }} + -
+

- {{ generatedLink }} + {{ generatedSignupLink }}

- {{ $t("general.close") }} + {{ $t("general.close") }} - +