fix: fix next and prev links not working

pull/130/head
Kia King Ishii 5 years ago committed by Kia Ishii
parent f56e745731
commit 07d8163649

@ -49,5 +49,6 @@ export default defineComponent({
margin-left: 4px;
width: 1rem;
height: 1rem;
transform: translateY(-1px);
}
</style>

@ -1,61 +0,0 @@
import { computed } from 'vue'
import { useRoute, useSiteData } from 'vitepress'
import { DefaultTheme } from '../config'
export default {
setup() {
const route = useRoute()
// TODO: could this be useSiteData<DefaultTheme.Config> or is the siteData
// resolved and has a different structure?
const siteData = useSiteData()
const resolveLink = (targetLink: string) => {
let target: DefaultTheme.SideBarLink | undefined
Object.keys(siteData.value.themeConfig.sidebar).some((k) => {
return siteData.value.themeConfig.sidebar[k].some(
(v: { children: any }) => {
if (Array.isArray(v.children)) {
target = v.children.find((value: any) => {
return value.link === targetLink
})
}
return !!target
}
)
})
return target
}
const next = computed(() => {
const pageData = route.data
if (pageData.frontmatter.next === false) {
return undefined
}
if (typeof pageData.frontmatter.next === 'string') {
return resolveLink(pageData.frontmatter.next)
}
return pageData.next
})
const prev = computed(() => {
const pageData = route.data
if (pageData.frontmatter.prev === false) {
return undefined
}
if (typeof pageData.frontmatter.prev === 'string') {
return resolveLink(pageData.frontmatter.prev)
}
return pageData.prev
})
const hasLinks = computed(() => {
return !!next || !!prev
})
return {
next,
prev,
hasLinks
}
}
}

@ -1,5 +1,6 @@
<template>
<div v-if="hasLinks" class="next-and-prev-link">
<div class="container">
<div class="prev">
<a v-if="prev" class="link" :href="prev.link">
<ArrowLeft class="icon icon-prev" />
@ -13,6 +14,7 @@
</a>
</div>
</div>
</div>
</template>
<script lang="ts">
@ -41,6 +43,10 @@ export default defineComponent({
<style scoped>
.next-and-prev-link {
padding-top: 1rem;
}
.container {
display: flex;
justify-content: space-between;
border-top: 1px solid var(--border-color);
@ -82,8 +88,8 @@ export default defineComponent({
.icon {
display: block;
flex-shrink: 0;
width: 1rem;
height: 1rem;
width: 16px;
height: 16px;
fill: var(--text-color);
}

@ -1,55 +1,42 @@
import { computed } from 'vue'
import { useRoute, useSiteData } from 'vitepress'
import { useSiteDataByRoute, usePageData } from 'vitepress'
import { DefaultTheme } from '../config'
export function useNextAndPrevLinks() {
const route = useRoute()
// TODO: could this be useSiteData<DefaultTheme.Config> or is the siteData
// resolved and has a different structure?
const siteData = useSiteData()
const resolveLink = (targetLink: string) => {
let target: DefaultTheme.SideBarLink | undefined
Object.keys(siteData.value.themeConfig.sidebar).some((k) => {
return siteData.value.themeConfig.sidebar[k].some(
(v: { children: any }) => {
if (Array.isArray(v.children)) {
target = v.children.find((value: any) => {
return value.link === targetLink
const site = useSiteDataByRoute()
const page = usePageData()
const candidates = computed(() => {
return getFlatSidebarLinks(site.value.themeConfig?.sidebar)
})
const currentPath = computed(() => {
return '/' + page.value.relativePath.replace(/(index)?\.(md|html)$/, '')
})
const currentIndex = computed(() => {
return candidates.value.findIndex((item) => {
return item.link === currentPath.value
})
}
return !!target
}
)
})
return target
}
const next = computed(() => {
const pageData = route.data
if (pageData.frontmatter.next === false) {
return undefined
if (
site.value.themeConfig?.nextLinks !== false &&
currentIndex.value > -1 &&
currentIndex.value < candidates.value.length - 1
) {
return candidates.value[currentIndex.value + 1]
}
if (typeof pageData.frontmatter.next === 'string') {
return resolveLink(pageData.frontmatter.next)
}
return pageData.next
})
const prev = computed(() => {
const pageData = route.data
if (pageData.frontmatter.prev === false) {
return undefined
}
if (typeof pageData.frontmatter.prev === 'string') {
return resolveLink(pageData.frontmatter.prev)
if (site.value.themeConfig?.prevLinks !== false && currentIndex.value > 0) {
return candidates.value[currentIndex.value - 1]
}
return pageData.prev
})
const hasLinks = computed(() => {
return !!next.value || !!prev.value
})
const hasLinks = computed(() => !!next.value || !!prev.value)
return {
next,
@ -57,3 +44,26 @@ export function useNextAndPrevLinks() {
hasLinks
}
}
function getFlatSidebarLinks(
sidebar?: DefaultTheme.SideBarConfig
): DefaultTheme.SideBarLink[] {
if (!sidebar || sidebar === 'auto') {
return []
}
return sidebar.reduce<DefaultTheme.SideBarLink[]>((links, item) => {
if (item.link) {
links.push({ text: item.text, link: item.link })
}
if ((item as DefaultTheme.SideBarGroup).children) {
links = [
...links,
...getFlatSidebarLinks((item as DefaultTheme.SideBarGroup).children)
]
}
return links
}, [])
}

@ -105,18 +105,13 @@ function createVitePressPlugin({
ctx.body = vueSrc
debug(ctx.url, ctx.status)
const pageDataWithLinks = {
...pageData,
// TODO: this doesn't work with locales
...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(pageDataWithLinks)
JSON.stringify(pageData)
)}`
}
return
@ -133,56 +128,6 @@ function createVitePressPlugin({
}
}
// TODO: share types from SideBarLink, SideBarGroup, etc. We are also assuming
// all themes follow this structure, in which case, we should expose the type
// instead of having any for themeConfig or not nest `sidebar` inside
// `themeConfig`, specially given it must be specified inside `locales` if there
// are any
interface SideBarLink {
text: string
link: string
}
function getNextAndPrev(themeConfig: any, pagePath: string) {
if (!themeConfig.sidebar) {
return
}
const sidebar = themeConfig.sidebar
let candidates: SideBarLink[] = []
Object.keys(sidebar).forEach((k) => {
if (!pagePath.startsWith(k)) {
return
}
sidebar[k].forEach((sidebarItem: { children?: SideBarLink[] }) => {
if (!sidebarItem.children) {
return
}
sidebarItem.children.forEach((candidate) => {
candidates.push(candidate)
})
})
})
const path = pagePath.replace(/\.(md|html)$/, '')
const currentLinkIndex = candidates.findIndex((v) => v.link === path)
const nextAndPrev: { prev?: SideBarLink; next?: SideBarLink } = {}
if (
themeConfig.nextLinks !== false &&
currentLinkIndex > -1 &&
currentLinkIndex < candidates.length - 1
) {
nextAndPrev.next = candidates[currentLinkIndex + 1]
}
if (themeConfig.prevLinks !== false && currentLinkIndex > 0) {
nextAndPrev.next = candidates[currentLinkIndex - 1]
}
return nextAndPrev
}
export async function createServer(options: ServerConfig = {}) {
const config = await resolveConfig(options.root)

2
types/shared.d.ts vendored

@ -29,8 +29,6 @@ export interface PageData {
headers: Header[]
relativePath: string
lastUpdated: number
next?: { text: string; link: string }
prev?: { text: string; link: string }
}
export interface Header {

Loading…
Cancel
Save