Skip to content

Commit bc4e0c0

Browse files
committed
✨ Add episode detail view with image retrieval
1 parent 0e78266 commit bc4e0c0

File tree

4 files changed

+89
-7
lines changed

4 files changed

+89
-7
lines changed

components/items/EpisodeItem.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,32 @@
22
import Image from "~/components/misc/Image.vue";
33
44
const props = defineProps<{
5-
episode: Episode
5+
episode: EpisodeWithProgression
66
}>();
77
</script>
88

99
<template>
10-
<NuxtLink class="flex h-20 border border-t-0 hover:cursor-pointer hover:bg-secondary md:h-24 lg:h-28">
11-
<Image :sum="episode.thumbnail"/>
10+
<NuxtLink
11+
class="flex h-20 border border-t-0 transition-colors hover:cursor-pointer md:h-24 lg:h-28"
12+
:class="[
13+
(episode.progression || 0) > 0 ? 'bg-amber-100/30' : 'hover:bg-secondary',
14+
]"
15+
:to="'/episode/' + episode.id"
16+
>
17+
<Image :sum="episode.thumbnail" />
1218
<div class="flex grow items-center justify-center p-2">
1319
<div class="flex grow items-center gap-2 md:w-[25rem] lg:w-[35rem]">
14-
<UiBadge v-if="props.episode.isNew" variant="default" class="h-max">New</UiBadge>
15-
<h4 class="truncate">{{episode.title}}</h4>
20+
<UiBadge
21+
v-if="props.episode.isNew"
22+
variant="default"
23+
class="h-max"
24+
>
25+
New
26+
</UiBadge>
27+
<h4 class="truncate">{{ episode.title }}</h4>
1628
</div>
1729
<div>
18-
<p class="opacity-50">#{{episode.number}}</p>
30+
<p class="opacity-50">#{{ episode.number }}</p>
1931
</div>
2032
</div>
2133
</NuxtLink>

pages/episode/[id].vue

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<script setup lang="ts">
2+
import Image from "~/components/misc/Image.vue";
3+
4+
const id = useRoute().params.id;
5+
const serverUrl = useLocalStorage("serverUrl", "");
6+
const router = useRouter();
7+
8+
// Récupération de l'épisode
9+
const {data: episode} = await useAsyncData<EpisodeWithProgression>(
10+
"episode",
11+
() => $fetch(`${serverUrl.value}/webtoons/episodes/${id}`), {server: false});
12+
13+
// Récupération des images de l'épisode
14+
const {data: images} = await useAsyncData<string[]>(
15+
"episode-images",
16+
() => $fetch(`${serverUrl.value}/webtoons/episodes/${id}/images`), {server: false});
17+
18+
</script>
19+
20+
<template>
21+
<div class="flex h-screen flex-col bg-background">
22+
<div class="flex items-center justify-between p-4 shadow-md">
23+
<NuxtLink class="flex items-center gap-2" @click="router.back">
24+
<UiButton variant="ghost" size="icon">
25+
<Icon name="iconoir:arrow-left" />
26+
</UiButton>
27+
<h1 class="text-xl font-semibold">{{ episode?.title }}</h1>
28+
</NuxtLink>
29+
</div>
30+
31+
<div class="flex-1 overflow-y-auto">
32+
<div class="max-w-3xl">
33+
<div
34+
v-for="(image, index) in (images || [])"
35+
:key="index"
36+
class="relative overflow-hidden rounded-lg shadow-xl"
37+
>
38+
<Image
39+
:sum="image"
40+
class="w-full object-contain"
41+
/>
42+
</div>
43+
</div>
44+
</div>
45+
</div>
46+
</template>

pages/webtoon/[id].vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import EpisodeItem from "~/components/items/EpisodeItem.vue";
3+
import type {EpisodeWithProgression} from "~/utils/types";
34
45
definePageMeta({
56
layout: "navigation",
@@ -13,14 +14,28 @@ const serverUrl = useLocalStorage("serverUrl", "");
1314
const {data: webtoon} = await useAsyncData<Webtoon>("webtoon", () => $fetch(`${serverUrl.value}/webtoons/${id}`), {
1415
server: false,
1516
});
16-
const {data: episodes} = await useAsyncData<Episode[]>("episodes", () => $fetch(`${serverUrl.value}/webtoons/${id}/episodes`), {
17+
const {data: episodes} = await useAsyncData<EpisodeWithProgression[]>("episodes", () => $fetch(`${serverUrl.value}/webtoons/${id}/episodes`), {
1718
server: false,
1819
});
20+
const token = useCookie("token").value;
21+
const {data: progressions} = await useAsyncData<Progression[]>("progressions", async() => {
22+
if(!token) return [];
23+
try{
24+
return await $fetch(`${serverUrl.value}/user/progression/webtoon/${id}`, {
25+
headers: {Authorization: `Bearer ${token}`}
26+
});
27+
}catch{
28+
return [];
29+
}
30+
}, {server: false});
1931
2032
const displayCount = ref(50);
2133
const displayedEpisodes = computed(() => {
2234
if(!episodes.value)
2335
return [];
36+
episodes.value.forEach((episode) => {
37+
episode.progression = progressions.value?.find((progression) => progression.episodeId === episode.id)?.progression ?? 0;
38+
});
2439
if(isIncreasing.value)
2540
return episodes.value.slice(-displayCount.value).reverse();
2641
return episodes.value.slice(0, displayCount.value);

utils/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,12 @@ export interface Episode{
1616
isNew: boolean
1717
thumbnail: string;
1818
}
19+
20+
export interface EpisodeWithProgression extends Episode{
21+
progression?: number;
22+
}
23+
24+
export interface Progression{
25+
episodeId: string;
26+
progression: number;
27+
}

0 commit comments

Comments
 (0)