| title | subtitle | category | layout |
|---|---|---|---|
Random rambling |
General non-technical pages |
blog |
pages-index |
Created
July 24, 2025 16:36
-
-
Save adiroiban/5705257e9f7acee0eba066a4357d0d43 to your computer and use it in GitHub Desktop.
VuePress blog pagination
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script setup lang="ts"> | |
| import {useData, withBase} from 'vitepress' | |
| import Footer from './components/Footer.vue' | |
| import Header from './components/Header.vue' | |
| const { params, frontmatter } = useData() | |
| </script> | |
| <template> | |
| <Header /> | |
| <div class="text-center"> | |
| <h2 class="text-3xl font-bold tracking-tight text-(--color-text-title) sm:text-4xl"> | |
| {{ frontmatter.title }} | |
| </h2> | |
| <p class="mx-auto mt-3 max-w-2xl text-xl text-(--color-text-main) sm:mt-4"> | |
| {{ frontmatter.subtitle }} | |
| </p> | |
| </div> | |
| <article v-for="page in params.content" class="flex flex-col overflow-hidden rounded-lg shadow-lg"> | |
| {{ page.frontmatter.title }} | |
| </article> | |
| <div class="mt-12 flex"> | |
| <div v-show="params.prevURL" class="mt-1"> | |
| <a :href="params.prevURL">Previous page</a> | |
| </div> | |
| <div v-show="params.nextURL" class="ml-auto text-right"> | |
| <a :href="params.nextURL">Next page</a> | |
| </div> | |
| </div> | |
| <Footer /> | |
| </template> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { getIndexPages } from '../../.vitepress/theme/utils' | |
| // My use case is more complicates as I have both /blog/*.md and /example/*.md | |
| export default getIndexPages(__dirname, '/blog', 10) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import fs from 'fs' | |
| import matter from 'gray-matter' | |
| export type PageMetadata = { | |
| path: string | |
| url: string | |
| frontmatter: any | |
| } | |
| export type IndexPage = { | |
| content: PageMetadata[] | |
| allPages: PageMetadata[] | |
| prevURL: string | |
| nextURL: string | |
| pageNumber: number | |
| } | |
| /** | |
| * Filter files that are not markdown content. | |
| */ | |
| function filterPage(path: string): boolean { | |
| // Online include markdownd files and explude path templates. | |
| return path.endsWith('.md') && !path.endsWith('].md') | |
| } | |
| function getFileMetadata(filePath: string, basePath: string, prefix: string): PageMetadata { | |
| const result = {path: filePath, url: '', frontmatter: {}} | |
| result.url = filePath.replace('.md', '').replace('\\', '/') | |
| result.url = `${prefix}/${result.url}.html` | |
| const src = fs.readFileSync(basePath + '/' + filePath, 'utf-8') | |
| result.frontmatter = matter(src).data | |
| return result | |
| } | |
| /** | |
| * Helper to be used in `index[counter].paths.ts` files. | |
| */ | |
| export function getIndexPages(srcPath: string, prefix: string, page_size: number = 10) { | |
| return { | |
| paths: () => { | |
| const allPages = fs | |
| .readdirSync(srcPath, { recursive: true }) | |
| .filter((file) => filterPage(file)) | |
| .map((file) => getFileMetadata(file, srcPath, prefix)) | |
| .sort((a, b) => b.frontmatter.date > a.frontmatter.date ? 1 : -1) | |
| const total = Math.ceil(allPages.length / page_size) | |
| return Array.from({length: total}).map((_, index) => { | |
| const current = index + 1 | |
| let prevURL = `index-${current - 1}.html` | |
| if (current === 1) { | |
| prevURL = '' | |
| } | |
| if (current === 2) { | |
| prevURL = 'index.html' | |
| } | |
| const nextURL = | |
| current < total ? `index-${current + 1}.html` : '' | |
| const cursor = current === 1 ? '' : `-${current}` | |
| const content = allPages.slice(index * page_size, (index + 1) * page_size) | |
| let indexPageContent: IndexPage = { | |
| content, | |
| allPages, | |
| prevURL, | |
| nextURL, | |
| pageNumber: current, | |
| } | |
| // cursor is used by vitepress to generate the path. | |
| // The other values are custom content. | |
| return {params: {cursor, ...indexPageContent}} | |
| }) | |
| }, | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment