1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-05 05:25:26 +02:00

feat: Remove Explore URLs and make the normal URLs public (#2632)

* add groupSlug to most routes

* fixed more routing issues

* fixed jank and incorrect routes

* remove public explore links

* remove unused groupSlug and explore routes

* nuked explore pages

* fixed public toolstore bug

* fixed various routes missing group slug

* restored public app header menu

* fix janky login redirect

* 404 recipe API call returns to login

* removed unused explore layout

* force redirect when using the wrong group slug

* fixed dead admin links

* removed unused middleware from earlier attempt

* 🧹

* improve cookbooks sidebar
fixed sidebar link not working
fixed sidebar link target
hide cookbooks header when there are none

* added group slug to user

* fix $auth typehints

* vastly simplified groupSlug logic

* allow logged-in users to view other groups

* fixed some edgecases that bypassed isOwnGroup

* fixed static home ref

* 🧹

* fixed redirect logic

* lint warning

* removed group slug from group and user pages
refactored all components to use route groupSlug or user group slug
moved some group pages to recipe pages

* fixed some bad types

* 🧹

* moved groupSlug routes under /g/groupSlug

* move /recipe/ to /r/

* fix backend url generation and metadata injection

* moved shopping lists to root/other route fixes

* changed shared from /recipes/ to /r/

* fixed 404 redirect not awaiting

* removed unused import

* fix doc links

* fix public recipe setting not affecting public API

* fixed backend tests

* fix nuxt-generate command

---------

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
Michael Genson 2023-11-05 19:07:02 -06:00 committed by GitHub
parent 94cf690e8f
commit 80968b02bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 555 additions and 501 deletions

View file

@ -6,14 +6,14 @@
v-model="sidebar"
absolute
:top-link="topLinks"
:secondary-header="$t('sidebar.cookbooks')"
:secondary-header-link="loggedIn ? '/group/cookbooks' : undefined"
:secondary-header="cookbookLinks.length ? $tc('sidebar.cookbooks') : undefined"
:secondary-header-link="isOwnGroup && cookbookLinks.length ? `/g/${groupSlug}/cookbooks` : undefined"
:secondary-links="cookbookLinks || []"
:bottom-links="isAdmin ? bottomLink : []"
:bottom-links="isAdmin ? bottomLinks : []"
>
<v-menu offset-y nudge-bottom="5" close-delay="50" nudge-right="15">
<template #activator="{ on, attrs }">
<v-btn v-if="loggedIn" rounded large class="ml-2 mt-3" v-bind="attrs" v-on="on">
<v-btn v-if="isOwnGroup" rounded large class="ml-2 mt-3" v-bind="attrs" v-on="on">
<v-icon left large color="primary">
{{ $globals.icons.createAlt }}
</v-icon>
@ -23,7 +23,7 @@
<v-list dense class="my-0 py-0">
<template v-for="(item, index) in createLinks">
<v-divider v-if="item.insertDivider" :key="index" class="mx-2"></v-divider>
<v-list-item v-if="!item.restricted || loggedIn" :key="item.title" :to="item.to" exact>
<v-list-item v-if="!item.restricted || isOwnGroup" :key="item.title" :to="item.to" exact>
<v-list-item-avatar>
<v-icon>
{{ item.icon }}
@ -64,7 +64,7 @@
</template>
</AppSidebar>
<AppHeader :menu="loggedIn">
<AppHeader>
<v-btn icon @click.stop="sidebar = !sidebar">
<v-icon> {{ $globals.icons.menu }}</v-icon>
</v-btn>
@ -79,6 +79,7 @@
<script lang="ts">
import { computed, defineComponent, onMounted, ref, useContext, useRoute } from "@nuxtjs/composition-api";
import { useLoggedInState } from "~/composables/use-logged-in-state";
import AppHeader from "@/components/Layout/LayoutParts/AppHeader.vue";
import AppSidebar from "@/components/Layout/LayoutParts/AppSidebar.vue";
import { SidebarLinks } from "~/types/application-types";
@ -91,13 +92,12 @@
components: { AppHeader, AppSidebar, LanguageDialog, TheSnackbar },
setup() {
const { $globals, $auth, $vuetify, i18n } = useContext();
const { isOwnGroup } = useLoggedInState();
const isAdmin = computed(() => $auth.user?.admin);
const loggedIn = computed(() => $auth.loggedIn);
const route = useRoute();
const groupSlug = route.value.params.groupSlug;
const { cookbooks } = loggedIn.value ? useCookbooks() : usePublicCookbooks(groupSlug);
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
const { cookbooks } = isOwnGroup.value ? useCookbooks() : usePublicCookbooks(groupSlug.value || "");
const toggleDark = useToggleDarkMode();
@ -115,7 +115,7 @@
return {
icon: $globals.icons.pages,
title: cookbook.name,
to: loggedIn.value ? `/cookbooks/${cookbook.slug as string}` : `/explore/cookbooks/${groupSlug}/${cookbook.slug as string}`,
to: `/g/${groupSlug.value}/cookbooks/${cookbook.slug as string}`,
};
});
});
@ -129,13 +129,13 @@
restricted: boolean;
}
const createLinks: Link[] = [
const createLinks = computed<Link[]>(() => [
{
insertDivider: false,
icon: $globals.icons.link,
title: i18n.tc("general.import"),
subtitle: i18n.tc("new-recipe.import-by-url"),
to: "/recipe/create/url",
to: `/g/${groupSlug.value}/r/create/url`,
restricted: true,
},
{
@ -143,7 +143,7 @@
icon: $globals.icons.edit,
title: i18n.tc("general.create"),
subtitle: i18n.tc("new-recipe.create-manually"),
to: "/recipe/create/new",
to: `/g/${groupSlug.value}/r/create/new`,
restricted: true,
},
{
@ -151,24 +151,24 @@
icon: $globals.icons.pages,
title: i18n.tc("sidebar.cookbook"),
subtitle: i18n.tc("sidebar.create-cookbook"),
to: "/group/cookbooks",
to: `/g/${groupSlug.value}/cookbooks`,
restricted: true,
},
];
]);
const bottomLinks: SidebarLinks = [
const bottomLinks = computed<SidebarLinks>(() => [
{
icon: $globals.icons.cog,
title: i18n.tc("general.settings"),
to: "/admin/site-settings",
restricted: true,
},
];
]);
const topLinks: SidebarLinks = [
const topLinks = computed<SidebarLinks>(() => [
{
icon: $globals.icons.search,
to: "/",
to: `/g/${groupSlug.value}`,
title: i18n.tc("sidebar.search"),
restricted: true,
},
@ -187,30 +187,41 @@
{
icon: $globals.icons.timelineText,
title: i18n.tc("recipe.timeline"),
to: "/group/timeline",
to: `/g/${groupSlug.value}/recipes/timeline`,
restricted: true,
},
{
icon: $globals.icons.categories,
to: "/recipes/categories",
to: `/g/${groupSlug.value}/recipes/categories`,
title: i18n.tc("sidebar.categories"),
restricted: true,
},
{
icon: $globals.icons.tags,
to: "/recipes/tags",
to: `/g/${groupSlug.value}/recipes/tags`,
title: i18n.tc("sidebar.tags"),
restricted: true,
},
{
icon: $globals.icons.potSteam,
to: "/recipes/tools",
to: `/g/${groupSlug.value}/recipes/tools`,
title: i18n.tc("tool.tools"),
restricted: true,
},
];
]);
return { cookbookLinks, createLinks, bottomLink: bottomLinks, topLinks, isAdmin, loggedIn, languageDialog, toggleDark, sidebar };
return {
groupSlug,
cookbookLinks,
createLinks,
bottomLinks,
topLinks,
isAdmin,
isOwnGroup,
languageDialog,
toggleDark,
sidebar,
};
},
});
</script>

View file

@ -35,7 +35,7 @@
<v-btn v-else icon @click="activateSearch">
<v-icon> {{ $globals.icons.search }}</v-icon>
</v-btn>
<v-btn v-if="$auth.loggedIn" :text="$vuetify.breakpoint.smAndUp" :icon="$vuetify.breakpoint.xs" @click="$auth.logout()">
<v-btn v-if="loggedIn" :text="$vuetify.breakpoint.smAndUp" :icon="$vuetify.breakpoint.xs" @click="$auth.logout()">
<v-icon :left="$vuetify.breakpoint.smAndUp">{{ $globals.icons.logout }}</v-icon>
{{ $vuetify.breakpoint.smAndUp ? $t("user.logout") : "" }}
</v-btn>
@ -49,6 +49,7 @@
<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, onMounted, ref, useContext, useRoute } from "@nuxtjs/composition-api";
import { useLoggedInState } from "~/composables/use-logged-in-state";
import RecipeDialogSearch from "~/components/Domain/Recipe/RecipeDialogSearch.vue";
export default defineComponent({
@ -61,14 +62,11 @@ export default defineComponent({
},
setup() {
const { $auth } = useContext();
const { loggedIn } = useLoggedInState();
const route = useRoute();
const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || "");
const loggedIn = computed(() => {
return $auth.loggedIn;
});
const groupSlug = route.value.params.groupSlug;
const routerLink = !loggedIn.value && groupSlug ? `/explore/recipes/${groupSlug}` : "/"
const routerLink = computed(() => groupSlug.value ? `/g/${groupSlug.value}` : "/");
const domSearchDialog = ref<InstanceType<typeof RecipeDialogSearch> | null>(null);
function activateSearch() {
@ -95,6 +93,7 @@ export default defineComponent({
activateSearch,
domSearchDialog,
routerLink,
loggedIn,
};
},
});

View file

@ -1,14 +1,14 @@
<template>
<v-navigation-drawer v-model="drawer" class="d-flex flex-column d-print-none" clipped app width="240px">
<!-- User Profile -->
<template v-if="$auth.user">
<v-list-item two-line to="/user/profile" exact>
<template v-if="loggedIn">
<v-list-item two-line :to="userProfileLink" exact>
<UserAvatar list :user-id="$auth.user.id" />
<v-list-item-content>
<v-list-item-title class="pr-2"> {{ $auth.user.fullName }}</v-list-item-title>
<v-list-item-subtitle>
<v-btn class="px-2 pa-0" text :to="`/user/${$auth.user.id}/favorites`" small>
<v-btn v-if="isOwnGroup" class="px-2 pa-0" text :to="userFavoritesLink" small>
<v-icon left small>
{{ $globals.icons.heart }}
</v-icon>
@ -26,7 +26,7 @@
<template v-if="topLink">
<v-list nav dense>
<template v-for="nav in topLink">
<div v-if="!nav.restricted || loggedIn" :key="nav.title">
<div v-if="!nav.restricted || isOwnGroup" :key="nav.title">
<!-- Multi Items -->
<v-list-group
v-if="nav.children"
@ -69,13 +69,20 @@
<!-- Secondary Links -->
<template v-if="secondaryLinks">
<v-subheader v-if="secondaryHeader" :to="secondaryHeaderLink" class="pb-0">
{{ secondaryHeader }}
</v-subheader>
<v-divider></v-divider>
<router-link v-if="secondaryHeader && secondaryHeaderLink" :to="secondaryHeaderLink" style="text-decoration: none;">
<v-subheader :to="secondaryHeaderLink" class="pb-0">
{{ secondaryHeader }}
</v-subheader>
</router-link>
<div v-else-if="secondaryHeader">
<v-subheader :to="secondaryHeaderLink" class="pb-0">
{{ secondaryHeader }}
</v-subheader>
</div>
<v-divider v-if="secondaryHeader"></v-divider>
<v-list nav dense exact>
<template v-for="nav in secondaryLinks">
<div v-if="!nav.restricted || loggedIn" :key="nav.title">
<div v-if="!nav.restricted || isOwnGroup" :key="nav.title">
<!-- Multi Items -->
<v-list-group
v-if="nav.children"
@ -116,7 +123,7 @@
<v-list nav dense>
<v-list-item-group v-model="bottomSelected" color="primary">
<template v-for="nav in bottomLinks">
<div v-if="!nav.restricted || loggedIn" :key="nav.title">
<div v-if="!nav.restricted || isOwnGroup" :key="nav.title">
<v-list-item
:key="nav.title"
exact
@ -141,6 +148,7 @@
<script lang="ts">
import { computed, defineComponent, reactive, toRefs, useContext } from "@nuxtjs/composition-api";
import { useLoggedInState } from "~/composables/use-logged-in-state";
import { SidebarLinks } from "~/types/application-types";
import UserAvatar from "~/components/Domain/User/UserAvatar.vue";
@ -198,7 +206,10 @@ export default defineComponent({
});
const { $auth } = useContext();
const loggedIn = computed(() => $auth.loggedIn);
const { loggedIn, isOwnGroup } = useLoggedInState();
const userFavoritesLink = computed(() => $auth.user ? `/user/${$auth.user.id}/favorites` : undefined);
const userProfileLink = computed(() => $auth.user ? "/user/profile" : undefined);
const state = reactive({
dropDowns: {},
@ -210,8 +221,11 @@ export default defineComponent({
return {
...toRefs(state),
userFavoritesLink,
userProfileLink,
drawer,
loggedIn,
isOwnGroup,
};
},
});