Skip to content

Commit

Permalink
feat: added support for manga w/ searches, caching etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jabster28 committed Jul 12, 2020
1 parent b781bb3 commit a02ee1c
Show file tree
Hide file tree
Showing 7 changed files with 388 additions and 5 deletions.
41 changes: 41 additions & 0 deletions src/components/MangaCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<transition
appear
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<q-card
:class="['q-ma-md', $q.screen.width > 400 ? 'col-2' : 'col-10']"
v-ripple
@click="goto('/manga/' + manga.mal_id)"
>
<q-img :src="manga.image_url">
<div class="absolute-bottom">
<div class="text-h6">{{ manga.title }}</div>
<div class="text-subtitle2">
{{ manga.type }}, {{ Math.round(manga.score) }} stars
</div>
</div>
</q-img>
</q-card>
</transition>
</template>

<script>
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
export default {
name: 'AnimeCard',
props: {
manga: {
type: Object,
required: true
}
},
methods: {
goto(e) {
this.$router.push(e);
}
}
};
</script>
16 changes: 16 additions & 0 deletions src/layouts/MainLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@
:key="link.title"
v-bind="link"
/>
<q-item-label header class="text-grey-8">
Manga
</q-item-label>
<EssentialLink
v-for="link in mangaLinks"
:key="link.title"
v-bind="link"
/>
<q-item-label header class="text-grey-8">
Users
</q-item-label>
Expand Down Expand Up @@ -143,6 +151,14 @@ export default {
link: '/search'
}
],
mangaLinks: [
{
title: 'Search',
caption: 'Search for a manga',
icon: 'search',
link: '/searchmanga'
}
],
userLinks: [
{
title: 'Me',
Expand Down
154 changes: 154 additions & 0 deletions src/pages/Manga.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<template>
<q-page class="items-center justify-evenly">
<div class="post">
<div v-if="error" class="error">
{{ error }}
</div>

<div v-if="manga.mal_id" class="content">
<div
:class="[
'q-mx-lg',
'items-center',
'justify-evenly',
$q.screen.width > 800 ? 'row' : 'col'
]"
>
<div class="col-5">
<q-img :src="manga.image_url" />
<q-btn
class="q-ma-lg"
color="primary"
clickable
type="a"
target="_blank"
:href="manga.url"
>
Open in MAL</q-btn
>
</div>
<div class="col-5">
<h2>{{ manga.title }}</h2>

<h6 class="disabled">{{ manga.title_english }}</h6>
<p class="text-justify">{{ manga.synopsis }}</p>
<h5>
<q-icon name="stars" />
{{ manga.score ? manga.score.toPrecision(3) : '-' }} / 10
</h5>
<h5>
<q-icon name="visibility" /> {{ norm(manga.members) || '0' }}
</h5>
<h5><q-icon name="star" /> {{ norm(manga.favorites) || '0' }}</h5>
<h5># {{ norm(manga.rank) || '-' }}</h5>
</div>
</div>
</div>
</div>
</q-page>
</template>

<script lang="ts">
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import axios from 'axios';
import Vue from 'vue';
export default Vue.extend({
name: 'PageManga',
data() {
return {
player: null,
manga: {
title: '',
mal_id: ''
},
error: ''
};
},
created() {
// fetch the data when the view is created and the data is
// already being observed
this.fetchData();
},
watch: {
// call again the method if the route changes
$route: 'fetchData'
},
methods: {
norm(x: number) {
if (!x) return;
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
fetchData() {
this.error = '';
this.$q.loading.show({
delay: 400 // ms
});
const currentManga = this.$route.params.id;
if (!navigator.onLine) {
console.log('checking for cached manga');
let cache = this.$q.localStorage.getItem('cache');
if (!cache) {
this.$q.localStorage.set('cache', {});
cache = this.$q.localStorage.getItem('cache');
}
/* @ts-ignore */
if (!cache.manga) cache.manga = {};
/* @ts-ignore */
if (cache.manga[this.$route.params.id]) {
if (currentManga != this.$route.params.id) return;
/* @ts-ignore */
console.log('found some');
/* @ts-ignore */
this.manga = cache.manga[this.$route.params.id];
this.$q.loading.hide();
return;
} else {
console.log('none found');
if (currentManga != this.$route.params.id) return;
this.$q.notify(
"This manga hasn't been cached, so we can't show you anything. Connect to the internet and try again."
);
this.$q.loading.hide();
return;
}
}
// replace `getPost` with your data fetching util / API wrapper
axios
.get(`https://api.jikan.moe/v3/manga/${this.$route.params.id}`)
.then(data => {
this.$q.loading.hide();
this.manga = data.data;
document.title = `${this.manga.title} | Mirai`;
/* @ts-ignore */
let cache = this.$q.localStorage.getItem('cache');
/* @ts-ignore */
if (!cache) {
this.$q.localStorage.set('cache', {});
cache = this.$q.localStorage.getItem('cache');
}
/* @ts-ignore */
if (!cache.manga) cache.manga = {};
/* @ts-ignore */
cache.manga[this.$route.params.id] = this.manga;
/* @ts-ignore */
cache.manga[this.$route.params.id].date = new Date();
if (currentManga != this.$route.params.id) return;
this.$q.localStorage.set('cache', cache);
})
.catch((e: string) => {
console.log(e);
this.$q.loading.hide();
this.error = e;
});
}
}
});
</script>
149 changes: 149 additions & 0 deletions src/pages/SearchManga.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<template>
<q-page class="row items-center justify-evenly">
<div class="row col-12 items-center justify-evenly">
<q-input
:class="['q-my-xl', $q.screen.width > 400 ? 'col-8' : 'col-10']"
v-model="searchmanga"
debounce="300"
filled
label="Enter a manga..."
:rules="[
val =>
!val ||
val.trim().length >= 3 ||
val.trim() == '' ||
'Minimum 3 characters.'
]"
@keypress="load"
:loading="loading"
clearable
autofocus
type="search"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
</div>

<q-space />
<div class="row items-center justify-evenly">
<MangaCard v-for="manga in results" :key="manga.mal_id" :manga="manga" />
</div>
</q-page>
</template>

<script lang="ts">
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import Vue from 'vue';
import MangaCard from 'components/MangaCard.vue';
import axios from 'axios';
export default Vue.extend({
name: 'PageSearchManga',
components: { MangaCard },
mounted() {
if (
this.$route.params.query &&
this.$route.params.query != this.searchmanga
) {
this.searchmanga = this.$route.params.query;
}
},
watch: {
searchmanga() {
document.title =
this.searchmanga && this.searchmanga.trim()
? `"${this.searchmanga}" | Search Mirai`
: 'Search Mirai';
if (
!this.$route.params.query ||
this.$route.params.query != this.searchmanga
) {
this.$router
.replace('/searchmanga/' + encodeURIComponent(this.searchmanga || ''))
.catch(e => console.log(e));
}
const currentSearch = this.searchmanga.trim();
this.loading = true;
if (!this.searchmanga || this.searchmanga.trim() == '') {
this.loading = false;
this.results = [];
return;
}
console.log('checking for cached searches');
let cache = this.$q.localStorage.getItem('cache');
if (!cache) {
this.$q.localStorage.set('cache', {});
cache = this.$q.localStorage.getItem('cache');
}
/* @ts-ignore */
if (!cache.searchmanga) cache.searchmanga = {};
/* @ts-ignore */
if (cache.searchmanga[this.searchmanga.trim()]) {
if (currentSearch != this.searchmanga.trim()) return;
/* @ts-ignore */
console.log('found some');
/* @ts-ignore */
this.results = cache.searchmanga[this.searchmanga.trim()];
this.loading = false;
if (!navigator.onLine) return;
} else {
console.log('none found');
if (!navigator.onLine) {
if (currentSearch != this.searchmanga.trim()) return;
this.$q.notify(
"This search hasn't been cached, so we can't show you anything. Connect to the internet and try again."
);
this.loading = false;
this.results = [];
return;
}
}
axios
.get(
`https://api.jikan.moe/v3/search/manga?q=${encodeURIComponent(
this.searchmanga.trim()
)}&page=1`
)
.then(e => {
/* @ts-ignore */
let cache = this.$q.localStorage.getItem('cache');
/* @ts-ignore */
if (!cache) {
this.$q.localStorage.set('cache', {});
cache = this.$q.localStorage.getItem('cache');
}
/* @ts-ignore */
if (!cache.searchmanga) cache.searchmanga = {};
/* @ts-ignore */
cache.searchmanga[this.searchmanga.trim()] = e.data.results;
/* @ts-ignore */
cache.searchmanga[this.searchmanga.trim()].date = new Date();
if (currentSearch.trim() != this.searchmanga.trim()) return;
this.$q.localStorage.set('cache', cache);
this.results = e.data.results;
this.loading = false;
})
.catch(e => console.log(e));
}
},
methods: {
load() {
this.loading = true;
}
},
data() {
return {
searchmanga: '',
results: [],
loading: false,
online: false
};
}
});
</script>
Loading

0 comments on commit a02ee1c

Please sign in to comment.