diff --git a/packages/@vuepress/plugin-pagination/.npmignore b/packages/@vuepress/plugin-pagination/.npmignore new file mode 100644 index 00000000..18f0a334 --- /dev/null +++ b/packages/@vuepress/plugin-pagination/.npmignore @@ -0,0 +1,2 @@ +__tests__ +__mocks__ \ No newline at end of file diff --git a/packages/@vuepress/plugin-pagination/README.md b/packages/@vuepress/plugin-pagination/README.md new file mode 100644 index 00000000..a4eabe69 --- /dev/null +++ b/packages/@vuepress/plugin-pagination/README.md @@ -0,0 +1,4 @@ +# @vuepress/plugin-pagination + +> pagination plugin for vuepress + diff --git a/packages/@vuepress/plugin-pagination/enhanceApp.js b/packages/@vuepress/plugin-pagination/enhanceApp.js new file mode 100644 index 00000000..f5b9af30 --- /dev/null +++ b/packages/@vuepress/plugin-pagination/enhanceApp.js @@ -0,0 +1,78 @@ +import paginationMeta from '@dynamic/pagination' + +class Pagination { + constructor (pagination, { pages, route }) { + let { postsFilter, postsSorter } = pagination + + /* eslint-disable no-eval */ + postsFilter = eval(postsFilter) + postsSorter = eval(postsSorter) + + const { path } = route + const { paginationPages } = pagination + + paginationPages.forEach((page, index) => { + if (page.path === path) { + this.paginationIndex = index + } + }) + + if (!this.paginationIndex) { + this.paginationIndex = 0 + } + + this._paginationPages = paginationPages + this._currentPage = paginationPages[this.paginationIndex] + this._posts = pages.filter(postsFilter).sort(postsSorter) + + console.log(this) + } + + get length () { + return this._paginationPages.length + } + + get posts () { + const [start, end] = this._currentPage.interval + return this._posts.slice(start, end) + } + + get hasPrev () { + return this.paginationIndex !== 0 + } + + get prevLink () { + if (this.hasPrev) { + return this._paginationPages[this.paginationIndex - 1].path + } + } + + get hasNext () { + return this.paginationIndex !== this.length - 1 + } + + get nextLink () { + if (this.hasNext) { + return this._paginationPages[this.paginationIndex + 1].path + } + } +} + +export default ({ + Vue, // the version of Vue being used in the VuePress app + options, // the options for the root Vue instance + router, // the router instance for the app + siteData // site metadata +}) => { + Vue.mixin({ + computed: { + $pagination () { + const { pages } = this.$site + const pagination = new Pagination(paginationMeta, { + pages, route: this.$route + }) + return pagination + } + } + }) +} diff --git a/packages/@vuepress/plugin-pagination/index.js b/packages/@vuepress/plugin-pagination/index.js new file mode 100644 index 00000000..3e7f8826 --- /dev/null +++ b/packages/@vuepress/plugin-pagination/index.js @@ -0,0 +1,72 @@ +const path = require('path') + +function getIntervallers (max, interval) { + const count = Math.floor(max / interval) + const arr = [...Array(count + 1)] + return arr.map((v, index) => { + const start = index * interval + const end = (index + 1) * interval - 1 + return [start, end > max ? max : end] + }) +} + +function withBase (base, path) { + if (path.charAt(0) === '/') { + return base + path.slice(1) + } else { + return path + } +} + +module.exports = (options, ctx) => ({ + enhanceAppFiles: [ + path.resolve(__dirname, 'enhanceApp.js') + ], + + ready () { + let { postsFilter, postsSorter } = options + postsFilter = postsFilter || (({ type }) => type === 'post') + postsSorter = postsSorter || ((prev, next) => { + const prevTime = new Date(prev.frontmatter.date).getTime() + const nextTime = new Date(next.frontmatter.date).getTime() + return prevTime - nextTime > 0 ? -1 : 1 + }) + + const { pages, base } = ctx + const posts = pages.filter(postsFilter) + const { + perPagePosts = 10, + paginationDir = 'page', + firstPagePath = '/', + layout = 'Layout' + } = options + + const normalizedfirstPagePath = withBase(base, firstPagePath) + const intervallers = getIntervallers(posts.length, perPagePosts) + const pagination = { + paginationPages: intervallers.map((interval, index) => { + const path = index === 0 + ? normalizedfirstPagePath + : `/${paginationDir}/${index + 1}/` + return { path, interval } + }), + postsFilter: postsFilter.toString(), + postsSorter: postsSorter.toString() + } + + ctx.pagination = pagination + pagination.paginationPages.forEach(({ path }) => { + ctx.addPage({ + permalink: path, + frontmatter: { layout } + }) + }) + }, + + async clientDynamicModules () { + return { + name: 'pagination.js', + content: `export default ${JSON.stringify(ctx.pagination, null, 2)}` + } + } +}) diff --git a/packages/@vuepress/plugin-pagination/package.json b/packages/@vuepress/plugin-pagination/package.json new file mode 100644 index 00000000..92615012 --- /dev/null +++ b/packages/@vuepress/plugin-pagination/package.json @@ -0,0 +1,25 @@ +{ + "name": "@vuepress/plugin-pagination", + "version": "1.0.0", + "description": "pagination plugin for vuepress", + "main": "index.js", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/vuejs/vuepress.git" + }, + "keywords": [ + "documentation", + "vue", + "vuepress", + "generator" + ], + "author": "Evan You", + "license": "MIT", + "bugs": { + "url": "https://github.com/vuejs/vuepress/issues" + }, + "homepage": "https://github.com/vuejs/vuepress/packages/@vuepress/plugin-pagination#readme" +} \ No newline at end of file