diff --git a/frontend/src/components/projects/ProjectPageMarkdown.vue b/frontend/src/components/projects/ProjectPageMarkdown.vue index 80a9cfd5..41b724e6 100644 --- a/frontend/src/components/projects/ProjectPageMarkdown.vue +++ b/frontend/src/components/projects/ProjectPageMarkdown.vue @@ -3,17 +3,23 @@ import type { ExtendedProjectPage, HangarProject, HangarProjectPage } from "~/ty const props = defineProps<{ project?: HangarProject; + page?: ExtendedProjectPage; mainPage: boolean; }>(); -const route = useRoute("user-project-pages-all"); +const route = useRoute("user-project-pages-page"); const router = useRouter(); const updateProjectPages = inject<(pages: HangarProjectPage[]) => void>("updateProjectPages"); -const { editingPage, changeEditingPage, page, savePage, deletePage } = await useProjectPage(route, router, props.project, props.mainPage); +const { editingPage, changeEditingPage, savePage, deletePage } = useProjectPage( + route, + router, + props.project, + props.mainPage ? props.project?.mainPage : props.page +); if (!props.mainPage) { - useHead(useSeo(page.value?.name + " | " + props.project?.name, props.project?.description, route, props.project?.avatarUrl)); + useHead(useSeo(props.page?.name + " | " + props.project?.name, props.project?.description, route, props.project?.avatarUrl)); } async function deletePageAndUpdateProject() { @@ -29,22 +35,10 @@ async function deletePageAndUpdateProject() { } defineSlots<{ - default: (props: { - page?: ExtendedProjectPage | null; - editingPage: boolean; - changeEditingPage: (editing: boolean) => void; - savePage: (content: string) => void; - deletePage: () => void; - }) => any; + default: (props: { editingPage: boolean; changeEditingPage: (editing: boolean) => void; savePage: (content: string) => void; deletePage: () => void }) => any; }>(); diff --git a/frontend/src/composables/useDataLoader.ts b/frontend/src/composables/useDataLoader.ts index a95733cc..76787fbc 100644 --- a/frontend/src/composables/useDataLoader.ts +++ b/frontend/src/composables/useDataLoader.ts @@ -1,7 +1,7 @@ import type { RouteLocationNormalized } from "vue-router"; -type dataLoaders = "user" | "project" | "version" | "organization"; -type routeParams = "user" | "project" | "version" | "organization"; +type dataLoaders = "user" | "project" | "version" | "organization" | "page"; +type routeParams = "user" | "project" | "version" | "organization" | "page"; // TODO check every handling of the reject stuff (for both composables) diff --git a/frontend/src/composables/useOpenProjectPages.ts b/frontend/src/composables/useOpenProjectPages.ts index cb1a14a0..a39fee46 100644 --- a/frontend/src/composables/useOpenProjectPages.ts +++ b/frontend/src/composables/useOpenProjectPages.ts @@ -1,7 +1,7 @@ import type { HangarProject } from "~/types/backend"; import type { RouteLocationTyped, RouteMapGeneric } from "vue-router"; -export function useOpenProjectPages(route: RouteLocationTyped, project?: HangarProject) { +export function useOpenProjectPages(route: RouteLocationTyped, project?: HangarProject) { const open = ref([]); watch( diff --git a/frontend/src/composables/useProjectPage.ts b/frontend/src/composables/useProjectPage.ts index a7dcddfb..84c081e5 100644 --- a/frontend/src/composables/useProjectPage.ts +++ b/frontend/src/composables/useProjectPage.ts @@ -1,14 +1,8 @@ -import type { HangarProject } from "~/types/backend"; +import type { ExtendedProjectPage, HangarProject } from "~/types/backend"; import type { Router } from "vue-router"; import type { RouteLocationNormalized } from "vue-router/auto"; -export async function useProjectPage(route: RouteLocationNormalized<"user-project-pages-all">, router: Router, project?: HangarProject, mainPage?: boolean) { - const page = mainPage ? computed(() => project?.mainPage) : usePage(() => ({ project: route.params.project, path: route.params.all?.toString() })).page; - // TODO fix this - // if (!page?.value) { - // throw useErrorRedirect(404, "Not found"); - // } - +export function useProjectPage(route: RouteLocationNormalized<"user-project-pages-page">, router: Router, project?: HangarProject, page?: ExtendedProjectPage) { const editingPage = ref(false); // Helper setter function, v-model cannot directly edit from inside a slot. @@ -17,21 +11,21 @@ export async function useProjectPage(route: RouteLocationNormalized<"user-projec } async function savePage(content: string) { - if (!page?.value) return; - await useInternalApi(`pages/save/${project?.id}/${page.value?.id}`, "post", { + if (!page) return; + await useInternalApi(`pages/save/${project?.id}/${page?.id}`, "post", { content, }).catch((e) => handleRequestError(e, "page.new.error.save")); - if (page.value && "contents" in page.value) { - page.value.contents = content; + if (page && "contents" in page) { + page.contents = content; } editingPage.value = false; } async function deletePage() { - if (!page?.value) return; - await useInternalApi(`pages/delete/${project?.id}/${page.value?.id}`, "post").catch((e) => handleRequestError(e, "page.new.error.save")); + if (!page) return; + await useInternalApi(`pages/delete/${project?.id}/${page?.id}`, "post").catch((e) => handleRequestError(e, "page.new.error.save")); await router.replace(`/${route.params.user}/${route.params.project}`); } - return { editingPage, changeEditingPage, page, savePage, deletePage }; + return { editingPage, changeEditingPage, savePage, deletePage }; } diff --git a/frontend/src/middleware/data.global.ts b/frontend/src/middleware/data.global.ts index 44884a62..fd347c8d 100644 --- a/frontend/src/middleware/data.global.ts +++ b/frontend/src/middleware/data.global.ts @@ -1,4 +1,4 @@ -import type { HangarOrganization, HangarProject, HangarVersion, User } from "~/types/backend"; +import type { ExtendedProjectPage, HangarOrganization, HangarProject, HangarVersion, User } from "~/types/backend"; import { useDataLoader } from "~/composables/useDataLoader"; import { isAxiosError } from "axios"; @@ -44,6 +44,20 @@ export default defineNuxtRouteMiddleware(async (to, from) => { promises ); + const { loader: pageLoader, data: page } = useDataLoader("page"); + const pageName = pageLoader( + "page", + to, + from, + async (pagePath) => { + if ("project" in to.params) { + return useInternalApi(`pages/page/${to.params.project}/` + pagePath.toString().replaceAll(",", "/")); + } + throw createError({ statusCode: 500, statusMessage: "No project param?!" }); + }, + promises + ) as string[] | undefined; + if (import.meta.server && promises?.length) { try { await Promise.all(promises); @@ -60,17 +74,23 @@ export default defineNuxtRouteMiddleware(async (to, from) => { let newPath = to.fullPath; if (userName) { if (user.value && user.value.name !== userName) { - newPath = newPath.replace(userName, user.value?.name); + newPath = newPath.replace(userName, user.value.name); } } if (projectName) { if (project.value && project.value.name !== projectName) { - newPath = newPath.replace(projectName, project.value?.name); + newPath = newPath.replace(projectName, project.value.name); } } if (versionName) { if (version.value && version.value.name !== versionName) { - newPath = newPath.replace(versionName, version.value?.name); + newPath = newPath.replace(versionName, version.value.name); + } + } + if (pageName) { + const pageSlug = pageName.join("/"); + if (page.value && page.value.slug !== pageSlug) { + newPath = newPath.replace(pageSlug, page.value.slug); } } if (newPath != to.fullPath) { diff --git a/frontend/src/pages/[user]/[project]/index.vue b/frontend/src/pages/[user]/[project]/index.vue index 8e706e3f..6fa27ff0 100644 --- a/frontend/src/pages/[user]/[project]/index.vue +++ b/frontend/src/pages/[user]/[project]/index.vue @@ -9,7 +9,7 @@ const props = defineProps<{ const config = useConfig(); const i18n = useI18n(); -const route = useRoute("user-project-pages-all"); +const route = useRoute("user-project-pages-page"); const openProjectPages = useOpenProjectPages(route, props.project); const sponsors = ref(props.project?.settings?.sponsors); @@ -65,12 +65,12 @@ useHead(