recursive navigation

This commit is contained in:
2025-10-15 00:22:53 +02:00
parent 3f6a58c0ed
commit d5e7b77103
7 changed files with 51 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
<template> <template>
<TrangaPage v-bind="$props"> <TrangaPage v-bind="$props" :back="backUrl ? { href: backUrl, icon: 'i-lucide-arrow-left', text: 'Back' } : undefined">
<template #left> <template #left>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<MangaCover v-if="manga" :manga="manga" class="self-center" /> <MangaCover v-if="manga" :manga="manga" class="self-center" />
@@ -10,9 +10,11 @@
</p> </p>
<USkeleton v-else class="text-xl h-20 w-full" /> <USkeleton v-else class="text-xl h-20 w-full" />
<div v-if="manga" class="flex flex-row gap-1 flex-wrap"> <div v-if="manga" class="flex flex-row gap-1 flex-wrap">
<UBadge v-for="author in manga.authors" :key="author.key" variant="outline" color="neutral">{{ author.name }}</UBadge> <UBadge v-for="author in manga.authors" :key="author.key" variant="outline" color="neutral"
><NuxtLink :to="`/manga/author/${author.key}?return=${path}`">{{ author.name }}</NuxtLink></UBadge
>
<UBadge v-for="tag in manga.tags" :key="tag" variant="outline" color="primary" <UBadge v-for="tag in manga.tags" :key="tag" variant="outline" color="primary"
><NuxtLink :to="`/manga/tag/${tag}`">{{ tag }}</NuxtLink></UBadge ><NuxtLink :to="`/manga/tag/${tag}?return=${path}`">{{ tag }}</NuxtLink></UBadge
> >
<NuxtLink v-for="link in manga.links" :key="link.key" :to="link.url" external no-prefetch> <NuxtLink v-for="link in manga.links" :key="link.key" :to="link.url" external no-prefetch>
<UBadge variant="outline" color="secondary">{{ link.provider }}</UBadge> <UBadge variant="outline" color="secondary">{{ link.provider }}</UBadge>
@@ -34,9 +36,11 @@
import type { components } from '#open-fetch-schemas/api'; import type { components } from '#open-fetch-schemas/api';
import TrangaPage, { type PageProps } from '~/components/TrangaPage.vue'; import TrangaPage, { type PageProps } from '~/components/TrangaPage.vue';
type Manga = components['schemas']['Manga']; type Manga = components['schemas']['Manga'];
const path = useRoute().fullPath;
export interface MangaDetailPageProps extends PageProps { export interface MangaDetailPageProps extends PageProps {
manga?: Manga; manga?: Manga;
backUrl?: string;
} }
defineProps<MangaDetailPageProps>(); defineProps<MangaDetailPageProps>();

View File

@@ -1,5 +1,5 @@
<template> <template>
<MangaDetailPage :manga="manga"> <MangaDetailPage :manga="manga" :back-url="backUrl">
<div class="grid gap-3 max-sm:grid-flow-row-dense min-sm:grid-cols-[70%_auto]"> <div class="grid gap-3 max-sm:grid-flow-row-dense min-sm:grid-cols-[70%_auto]">
<ChaptersList :manga-id="mangaId" /> <ChaptersList :manga-id="mangaId" />
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
@@ -67,9 +67,11 @@
<script setup lang="ts"> <script setup lang="ts">
import MangaDetailPage from '~/components/MangaDetailPage.vue'; import MangaDetailPage from '~/components/MangaDetailPage.vue';
const { $api } = useNuxtApp();
const route = useRoute(); const route = useRoute();
const mangaId = route.params.mangaId as string; const mangaId = route.params.mangaId as string;
const { $api } = useNuxtApp(); const backUrl = route.query.return as string | undefined;
const flashDownloading = route.query.download; const flashDownloading = route.query.download;
const { data: manga } = await useApi('/v2/Manga/{MangaId}', { const { data: manga } = await useApi('/v2/Manga/{MangaId}', {

View File

@@ -24,6 +24,7 @@
const route = useRoute(); const route = useRoute();
const targetId = route.params.targetId as string; const targetId = route.params.targetId as string;
const mangaId = route.params.mangaId as string; const mangaId = route.params.mangaId as string;
const path = route.fullPath;
const { $api } = useNuxtApp(); const { $api } = useNuxtApp();
const reverse = ref(false); const reverse = ref(false);
@@ -34,7 +35,7 @@ const merge = async () => {
const from = reverse.value ? mangaId : targetId; const from = reverse.value ? mangaId : targetId;
const to = reverse.value == false ? targetId : mangaId; const to = reverse.value == false ? targetId : mangaId;
await $api('/v2/Manga/{MangaIdFrom}/MergeInto/{MangaIdInto}', { method: 'POST', path: { MangaIdFrom: from, MangaIdInto: to } }); await $api('/v2/Manga/{MangaIdFrom}/MergeInto/{MangaIdInto}', { method: 'POST', path: { MangaIdFrom: from, MangaIdInto: to } });
navigateTo(`/manga/${to}`); navigateTo(`/manga/${to}?return=${path}`);
}; };
useHead({ title: 'Confirm merge' }); useHead({ title: 'Confirm merge' });

View File

@@ -1,13 +1,18 @@
<template> <template>
<MangaDetailPage :manga="manga" :back="{ text: 'Back', href: `/manga/${mangaId}`, icon: 'i-lucide-arrow-left' }" title="Merge with"> <MangaDetailPage
:manga="manga"
:back="{ text: 'Back', href: backUrl ?? `/manga/${mangaId}`, icon: 'i-lucide-arrow-left' }"
title="Merge with">
<USkeleton v-if="!mangas" class="w-full h-[350px]" /> <USkeleton v-if="!mangas" class="w-full h-[350px]" />
<MangaCardList :manga="mangas" @click="(m) => navigateTo(`/manga/${mangaId}/merge/${m.key}`)" /> <MangaCardList :manga="mangas" @click="(m) => navigateTo(`/manga/${mangaId}/merge/${m.key}?return=${path}`)" />
</MangaDetailPage> </MangaDetailPage>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const route = useRoute(); const route = useRoute();
const mangaId = route.params.mangaId as string; const mangaId = route.params.mangaId as string;
const backUrl = route.query.return as string | undefined;
const path = route.fullPath;
const { data: manga } = await useApi('/v2/Manga/{MangaId}', { path: { MangaId: mangaId }, key: FetchKeys.Manga.Id(mangaId) }); const { data: manga } = await useApi('/v2/Manga/{MangaId}', { path: { MangaId: mangaId }, key: FetchKeys.Manga.Id(mangaId) });
const { data: mangas } = await useApi('/v2/Manga', { key: FetchKeys.Manga.All }); const { data: mangas } = await useApi('/v2/Manga', { key: FetchKeys.Manga.All });

View File

@@ -0,0 +1,23 @@
<template>
<TrangaPage :back="backUrl ? { href: backUrl, icon: 'i-lucide-arrow-left', text: 'Back' } : undefined">
<template #title>
<h1 class="text-2xl">
Manga with Author <UBadge variant="outline" color="neutral" class="font-semibold text-xl ml-1">{{ author?.name }}</UBadge>
</h1>
</template>
<LoadingPage :loading="status === 'pending'">
<MangaCardList :manga="manga" @click="(m) => navigateTo(`/manga/${m.key}?return=${route.fullPath}`)" />
</LoadingPage>
</TrangaPage>
</template>
<script setup lang="ts">
const route = useRoute();
const authorId = route.params.authorId as string;
const backUrl = route.query.return as string | undefined;
const { data: author } = await useApi('/v2/Author/{AuthorId}', { path: { AuthorId: authorId } });
const { data: manga, status } = await useApi('/v2/Manga/WithAuthorId/{AuthorId}', { path: { AuthorId: authorId }, lazy: true });
useHead({ title: 'Author Search' });
</script>

View File

@@ -1,12 +1,12 @@
<template> <template>
<TrangaPage> <TrangaPage :back="backUrl ? { href: backUrl, icon: 'i-lucide-arrow-left', text: 'Back' } : undefined">
<template #title> <template #title>
<h1 class="text-2xl"> <h1 class="text-2xl">
Manga with Tag <UBadge variant="outline" class="text-primary font-semibold text-xl">{{ tag }}</UBadge> Manga with Tag <UBadge variant="outline" color="primary" class="font-semibold text-xl ml-1">{{ tag }}</UBadge>
</h1> </h1>
</template> </template>
<LoadingPage :loading="status === 'pending'"> <LoadingPage :loading="status === 'pending'">
<MangaCardList :manga="manga" /> <MangaCardList :manga="manga" @click="(m) => navigateTo(`/manga/${m.key}?return=${route.fullPath}`)" />
</LoadingPage> </LoadingPage>
</TrangaPage> </TrangaPage>
</template> </template>
@@ -14,7 +14,8 @@
<script setup lang="ts"> <script setup lang="ts">
const route = useRoute(); const route = useRoute();
const tag = route.params.tag as string; const tag = route.params.tag as string;
const backUrl = route.query.return as string | undefined;
const { data: manga, status } = await useApi('/v2/Manga/WithTag/{Tag}', { path: { Tag: tag }, lazy: true }); const { data: manga, status } = await useApi('/v2/Manga/WithTag/{Tag}', { path: { Tag: tag }, lazy: true });
useHead({ title: 'Tranga' }); useHead({ title: 'Tag search' });
</script> </script>

View File

@@ -41,7 +41,7 @@
:expanded="i === expanded" :expanded="i === expanded"
@click="expanded = expanded === i ? -1 : i"> @click="expanded = expanded === i ? -1 : i">
<template #actions="manga"> <template #actions="manga">
<UButton :to="`/manga/${manga.key}?download=true`">Download</UButton> <UButton :to="`/manga/${manga.key}?download=true&return=${path}`">Download</UButton>
</template> </template>
</MangaCard> </MangaCard>
</div> </div>
@@ -56,6 +56,8 @@ import type { StepperItem } from '@nuxt/ui';
type MangaConnector = components['schemas']['MangaConnector']; type MangaConnector = components['schemas']['MangaConnector'];
type MinimalManga = components['schemas']['MinimalManga']; type MinimalManga = components['schemas']['MinimalManga'];
const path = useRoute().fullPath;
const { data: connectors } = await useApi('/v2/MangaConnector', { key: FetchKeys.MangaConnector.All }); const { data: connectors } = await useApi('/v2/MangaConnector', { key: FetchKeys.MangaConnector.All });
const query = ref<string>(); const query = ref<string>();