mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-10-15 01:40:46 +02:00
Loadingpage
MangaCardList Manga with Tag Page
This commit is contained in:
20
website/app/components/LoadingPage.vue
Normal file
20
website/app/components/LoadingPage.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<UPageBody v-if="loading">
|
||||||
|
<UPageHero title="Loading..." />
|
||||||
|
</UPageBody>
|
||||||
|
<UPageBody v-else v-bind="$props">
|
||||||
|
<template v-for="(_, slotName) in $slots" #[slotName]>
|
||||||
|
<slot :name="slotName" />
|
||||||
|
</template>
|
||||||
|
</UPageBody>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PageBodyProps } from '#ui/components/PageBody.vue';
|
||||||
|
|
||||||
|
export interface LoadingPageProps extends PageBodyProps {
|
||||||
|
loading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<LoadingPageProps>();
|
||||||
|
</script>
|
16
website/app/components/MangaCardList.vue
Normal file
16
website/app/components/MangaCardList.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<MangaCard v-for="(m, i) in manga" :key="m.key" :manga="m" :expanded="i === expanded" @click="expanded = expanded === i ? -1 : i">
|
||||||
|
<template #actions="forManga">
|
||||||
|
<UButton :to="`manga/${forManga.key}`">Details</UButton>
|
||||||
|
</template>
|
||||||
|
</MangaCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { components } from '#open-fetch-schemas/api';
|
||||||
|
type Manga = components['schemas']['Manga'];
|
||||||
|
type MinimalManga = components['schemas']['MinimalManga'];
|
||||||
|
|
||||||
|
const expanded = ref(-1);
|
||||||
|
defineProps<{manga?: (MinimalManga | Manga)[]}>()
|
||||||
|
</script>
|
@@ -11,7 +11,7 @@
|
|||||||
<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">{{ author.name }}</UBadge>
|
||||||
<UBadge v-for="tag in manga.tags" :key="tag" variant="outline" color="primary">{{ tag }}</UBadge>
|
<UBadge v-for="tag in manga.tags" :key="tag" variant="outline" color="primary"><NuxtLink :to="`/manga/tag/${tag}`">{{ 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>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<UPageBody>
|
||||||
<h1>{{ error?.statusCode }}</h1>
|
<UPageHero :title="error?.statusCode??'Error'">
|
||||||
<p>{{ error?.message }}</p>
|
<p>{{ error?.message }}</p>
|
||||||
<NuxtLink to="/">Go back home</NuxtLink>
|
<NuxtLink to="/">Go back home</NuxtLink>
|
||||||
<NuxtLink to="https://github.com/C9Glax/tranga-website/issues/new"><Icon name="i-lucide-github" />Report this issue</NuxtLink>
|
<NuxtLink to="https://github.com/C9Glax/tranga-website/issues/new"><Icon name="i-lucide-github" />Report this issue</NuxtLink>
|
||||||
</div>
|
</UPageHero>
|
||||||
|
</UPageBody>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@@ -1,17 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<UPageBody class="p-4 flex flex-row flex-wrap gap-6 mt-0">
|
<LoadingPage :loading="status === 'pending'" class="p-4 flex flex-row flex-wrap gap-6 mt-0">
|
||||||
<MangaCard v-for="(m, i) in manga" :key="m.key" :manga="m" :expanded="i === expanded" @click="expanded = expanded === i ? -1 : i">
|
<MangaCardList :manga="manga" />
|
||||||
<template #actions="formanga">
|
</LoadingPage>
|
||||||
<UButton :to="`manga/${formanga.key}`">Details</UButton>
|
|
||||||
</template>
|
|
||||||
</MangaCard>
|
|
||||||
</UPageBody>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { data: manga, refresh } = await useApi('/v2/Manga', { key: FetchKeys.Manga.All, lazy: true });
|
const { data: manga, refresh, status } = await useApi('/v2/Manga', { key: FetchKeys.Manga.All, lazy: true });
|
||||||
onMounted(() => refresh());
|
onMounted(() => refresh());
|
||||||
const expanded = ref(-1);
|
|
||||||
|
|
||||||
useHead({ title: 'Tranga' });
|
useHead({ title: 'Tranga' });
|
||||||
</script>
|
</script>
|
||||||
|
15
website/app/pages/manga/tag/[tag].vue
Normal file
15
website/app/pages/manga/tag/[tag].vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<LoadingPage :loading="status === 'pending'" class="p-4 flex flex-row flex-wrap gap-6 mt-0">
|
||||||
|
<UButton variant="soft" to="/" icon="i-lucide-arrow-left">Home</UButton>
|
||||||
|
<h1 class="text-2xl">Manga with Tag <span class="text-primary font-semibold">{{ tag }}</span></h1>
|
||||||
|
<MangaCardList :manga="manga" />
|
||||||
|
</LoadingPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const route = useRoute();
|
||||||
|
const tag = route.params.tag as string;
|
||||||
|
const { data: manga, status } = await useApi('/v2/Manga/WithTag/{Tag}', { path: { Tag: tag } });
|
||||||
|
|
||||||
|
useHead({ title: 'Tranga' });
|
||||||
|
</script>
|
@@ -85,16 +85,19 @@ const connectorClick = (c: MangaConnector) => {
|
|||||||
const searchResult = useState<MinimalManga[]>(() => []);
|
const searchResult = useState<MinimalManga[]>(() => []);
|
||||||
const expanded = useState(() => -1);
|
const expanded = useState(() => -1);
|
||||||
const searchQuery = useState<string>(() => '');
|
const searchQuery = useState<string>(() => '');
|
||||||
const performSearch = () => {
|
const performSearch = async () => {
|
||||||
if (!query.value) return;
|
if (!query.value) return;
|
||||||
busy.value = true;
|
busy.value = true;
|
||||||
searchQuery.value = query.value;
|
searchQuery.value = query.value;
|
||||||
search(query.value)
|
await search(query.value)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
searchResult.value = data;
|
searchResult.value = data;
|
||||||
activeStep.value = 2;
|
activeStep.value = 2;
|
||||||
})
|
})
|
||||||
.finally(() => (busy.value = false));
|
.finally(() => {
|
||||||
|
refreshNuxtData(FetchKeys.Manga.All);
|
||||||
|
busy.value = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const search = async (query: string): Promise<MinimalManga[]> => {
|
const search = async (query: string): Promise<MinimalManga[]> => {
|
||||||
|
Reference in New Issue
Block a user