feat: add prev/next links (#56)

* feat: set Prev/Next to page data
* feat: set links at the bottom of page
* feat: hide next/prev links when themeConfig expressly set false
pull/77/head
Yugo Ogura 4 years ago committed by GitHub
parent 5419abdcc6
commit f52b1d576b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,22 @@
import { defineComponent, computed } from 'vue'
import { usePageData } from 'vitepress'
export default defineComponent({
setup() {
const pageData = usePageData()
const next = computed(() => {
return pageData.value.next
})
const prev = computed(() => {
return pageData.value.prev
})
const hasLinks = computed(() => {
return !!next || !!prev
})
return {
next,
prev,
hasLinks
}
}
})

@ -0,0 +1,25 @@
<template>
<div v-if="hasLinks" class="links-wrapper">
<div class="prev-link">
<div v-if="prev">
<a :href="prev.link">{{prev.text}}</a>
</div>
</div>
<div class="next-link">
<div v-if="next">
<a :href="next.link">{{next.text}}</a>
</div>
</div>
</div>
</template>
<script src="./NextAndPrevLinks"></script>
<style>
.links-wrapper {
padding-top: 1rem;
padding-bottom: 1rem;
display: flex;
justify-content: space-between;
}
</style>

@ -1,9 +1,17 @@
<template>
<div class="content">
<Content />
<NextAndPrevLinks />
</div>
</template>
<script>
import NextAndPrevLinks from './NextAndPrevLinks.vue'
export default {
components:{ NextAndPrevLinks }
}
</script>
<style>
.content {
max-width: 46rem;

@ -104,13 +104,17 @@ function createVitePressPlugin({
ctx.body = vueSrc
debug(ctx.url, ctx.status)
const pageDataWithLinks = {
...pageData,
...getNextAndPrev(siteData.themeConfig, ctx.path)
}
await next()
// make sure this is the main <script> block
if (!ctx.query.type) {
// inject pageData to generated script
ctx.body += `\nexport const __pageData = ${JSON.stringify(
JSON.stringify(pageData)
JSON.stringify(pageDataWithLinks)
)}`
}
return
@ -127,6 +131,41 @@ function createVitePressPlugin({
}
}
function getNextAndPrev(themeConfig: any, pagePath: string) {
if (!themeConfig.sidebar) {
return
}
const sidebar = themeConfig.sidebar
let candidates: { text: string; link: string }[] = []
Object.keys(sidebar).forEach((k) => {
if (!pagePath.startsWith(k)) {
return
}
sidebar[k].forEach((sidebarItem: { [key: string]: any }) => {
if (!sidebarItem.children) {
return
}
sidebarItem.children.forEach((candidate: any) => {
candidates.push(candidate)
})
})
})
const path = pagePath.replace(/\.(md|html)$/, '')
const currentLinkIndex = candidates.findIndex((v) => v.link === path)
const hideNextLink = themeConfig.nextLinks === false
const hidePrevLink = themeConfig.prevLinks === false
return {
...(currentLinkIndex !== -1 && !hideNextLink
? { next: candidates[currentLinkIndex + 1] }
: {}),
...(currentLinkIndex !== -1 && !hidePrevLink
? { prev: candidates[currentLinkIndex - 1] }
: {})
}
}
export async function createServer(options: ServerConfig = {}) {
const config = await resolveConfig(options.root)

2
types/shared.d.ts vendored

@ -26,6 +26,8 @@ export interface PageData {
frontmatter: Record<string, any>
headers: Header[]
lastUpdated: number
next?: { text: string; link: string }
prev?: { text: string; link: string }
}
export interface Header {

Loading…
Cancel
Save