Add pagination feature for blog post

Signed-off-by: Al Asad Nur Riyad <alasadnurriyad@Als-MacBook-Pro.local>
This commit is contained in:
Al Asad Nur Riyad
2023-08-05 01:18:51 +06:00
parent 57b033fe52
commit 47b6a1f456
5 changed files with 104 additions and 15 deletions

View File

@@ -0,0 +1,23 @@
<script>
import { ContentLoader } from 'vue-content-loader'
export default {
components: { ContentLoader },
}
</script>
<template>
<ContentLoader
viewBox="0 0 400 160"
:speed="2"
primary-color="#c9c9c9"
secondary-color="#ecebeb"
>
<rect x="10" y="13" rx="0" ry="0" width="95" height="86" />
<rect x="119" y="19" rx="0" ry="0" width="219" height="16" />
<rect x="119" y="49" rx="0" ry="0" width="277" height="16" />
<rect x="119" y="82" rx="0" ry="0" width="56" height="14" />
<rect x="195" y="82" rx="0" ry="0" width="56" height="14" />
<rect x="272" y="82" rx="0" ry="0" width="56" height="14" />
</ContentLoader>
</template>

View File

@@ -11,6 +11,7 @@
},
"devDependencies": {
"@antfu/eslint-config": "^0.38.5",
"@formkit/auto-animate": "^0.7.0",
"@nuxt/content": "^2.7.2",
"@nuxt/image-edge": "^1.0.0-27840416.dc1ed65",
"@nuxtjs/fontaine": "^0.2.5",
@@ -21,6 +22,7 @@
"nuxt": "^3.6.5",
"nuxt-icon": "^0.4.0",
"nuxt-simple-sitemap": "^3.1.3",
"typescript": "^5.0.4"
"typescript": "^5.0.4",
"vue-content-loader": "^2.0.1"
}
}

View File

@@ -1,6 +1,9 @@
<script lang="ts" setup>
const { data } = await useAsyncData('home', () => queryContent('/blogs').sort({ _id: -1 }).find())
const elementPerPgae = ref(4)
const pageNumber = ref(1)
const formatedData = computed(() => {
return data.value?.map((articles) => {
return {
@@ -14,9 +17,36 @@ const formatedData = computed(() => {
tags: articles.tags || [],
published: articles.published || false,
}
})
}) || []
})
const paginatedData = computed(() => {
return formatedData.value.filter((data, idx) => {
const startInd = ((pageNumber.value - 1) * elementPerPgae.value)
const endInd = (pageNumber.value * elementPerPgae.value) - 1
if (idx >= startInd && idx <= endInd)
return true
else return false
}) || []
})
function onPreviousPageClick() {
if (pageNumber.value > 1)
pageNumber.value -= 1
}
const isNextpageAvailable = computed(() => {
if (pageNumber.value * elementPerPgae.value <= formatedData.value.length)
return true
else return false
})
function onNextPageClick() {
if (isNextpageAvailable.value)
pageNumber.value += 1
}
useHead({
title: 'Archive',
meta: [
@@ -32,20 +62,38 @@ useHead({
<template>
<main class="container max-w-5xl mx-auto text-zinc-600">
<ArchiveHero />
<div class="space-y-5 my-5">
<template v-for="post in formatedData" :key="post.title">
<ArchiveCard
:path="post.path"
:title="post.title"
:date="post.date"
:description="post.description"
:image="post.image"
:alt="post.alt"
:og-image="post.ogImage"
:tags="post.tags"
:published="post.published"
/>
<ClientOnly>
<div v-auto-animate class="space-y-5 my-5">
<template v-for="post in paginatedData" :key="post.title">
<ArchiveCard
:path="post.path"
:title="post.title"
:date="post.date"
:description="post.description"
:image="post.image"
:alt="post.alt"
:og-image="post.ogImage"
:tags="post.tags"
:published="post.published"
/>
</template>
</div>
<template #fallback>
<!-- this will be rendered on server side -->
<BlogLoader />
<BlogLoader />
</template>
</ClientOnly>
<div class="flex justify-center items-center space-x-6">
<button :disabled="pageNumber <= 1" @click="onPreviousPageClick">
<Icon name="mdi:code-less-than" size="30" :class="{ 'text-sky-700': pageNumber > 1 }" />
</button>
<p>{{ pageNumber }}</p>
<button :disabled="!isNextpageAvailable" @click="onNextPageClick">
<Icon name="mdi:code-greater-than" size="30" :class="{ 'text-sky-700': isNextpageAvailable }" />
</button>
</div>
</main>
</template>

6
plugins/formik.client.ts Normal file
View File

@@ -0,0 +1,6 @@
import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
export default defineNuxtPlugin((nuxtApp) => {
// Doing something with nuxtApp
nuxtApp.vueApp.use(autoAnimatePlugin)
})

View File

@@ -642,6 +642,11 @@
resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz#c1c66b3b771c09742a54dd5bc87c582f6b0630ff"
integrity sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==
"@formkit/auto-animate@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@formkit/auto-animate/-/auto-animate-0.7.0.tgz#7a68df578e972d63d999378571ce6e012d9059ae"
integrity sha512-RczHUr0AhRPssREoNdRjLfk2b/id9/DFnbIq18QM8L7E4zNV3XH+WO480EZ46BQHDEsv76YPJ0JbG2Y2i3GfXw==
"@humanwhocodes/config-array@^0.11.10":
version "0.11.10"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
@@ -8330,6 +8335,11 @@ vue-bundle-renderer@^1.0.3:
dependencies:
ufo "^1.1.1"
vue-content-loader@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/vue-content-loader/-/vue-content-loader-2.0.1.tgz#c6a3ff0e653671e5e8cff9e0c3814e6d04d3411d"
integrity sha512-pkof4+q2xmzNEdhqelxtJejeP/vQUJtLle4/v2ueG+HURqM9Q/GIGC8GJ2bVVWeLfTDET51jqimwQdmxJTlu0g==
vue-devtools-stub@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz#a65b9485edecd4273cedcb8102c739b83add2c81"