From 9a065a115b5e71cfb83f4287f38d1a03dbba0eda Mon Sep 17 00:00:00 2001 From: Florian Pichler Date: Wed, 21 Aug 2019 12:17:14 +0200 Subject: [PATCH] Blog index pagination (#690) * Allow ArrowLink to be reversed for pagination * make blog components and template more generic * split blog posts into pages * make pagination links work * make bundle split patterns more flexbile * bundle blog posts with respective pages * make blog page of each post its parent bundle * drop blog.js bundle * cache blog bundles in service worker * format --- config/routes-map.js | 55 ++++++++++------ ember-cli-build.js | 39 ++++++++---- lib/generate-blog/lib/collect-posts.js | 6 +- lib/generate-blog/lib/components-builder.js | 37 ++++++++--- .../{start-page => list-page}/stylesheet.hbs | 5 +- .../{start-page => list-page}/template.hbs | 63 +++++++++++-------- lib/service-workers/lib/worker-builder.js | 2 +- lib/service-workers/workers/service-worker.js | 1 - src/ui/components/ArrowLink/stylesheet.css | 24 +++++++ src/ui/components/ArrowLink/template.hbs | 2 +- src/ui/styles/blocks/pagination.block.css | 6 ++ 11 files changed, 169 insertions(+), 71 deletions(-) rename lib/generate-blog/lib/templates/{start-page => list-page}/stylesheet.hbs (80%) rename lib/generate-blog/lib/templates/{start-page => list-page}/template.hbs (64%) create mode 100644 src/ui/styles/blocks/pagination.block.css diff --git a/config/routes-map.js b/config/routes-map.js index 33eed8b35d..f7508ad55d 100644 --- a/config/routes-map.js +++ b/config/routes-map.js @@ -1,24 +1,13 @@ 'use strict'; const path = require('path'); + +const _ = require('lodash'); + const collectPosts = require('../lib/generate-blog/lib/collect-posts'); module.exports = function() { let { posts, authors } = collectPosts(path.join(__dirname, '..', '_posts')); - let blogPostRoutes = posts.reduce((acc, post) => { - acc[`/blog/${post.queryPath}`] = { - component: post.componentName, - bundle: { - asset: `/blog/${post.queryPath}.js`, - module: `__blog-${post.queryPath}__`, - }, - parentBundle: { - asset: '/blog.js', - }, - }; - return acc; - }, {}); - let blogAuthorsRoutes = authors.reduce((acc, author) => { acc[`/blog/author/${author.twitter}`] = { component: author.componentName, @@ -26,19 +15,49 @@ module.exports = function() { asset: `/blog/author-${author.twitter}.js`, module: `__blog-author-${author.twitter}__`, }, - parentBundle: { - asset: '/blog.js', - }, }; return acc; }, {}); + let blogPages = _.chunk(posts, 10); + let blogPostRoutes = {}; + let blogPagesRoutes = {}; + blogPages.forEach((pagePosts, i) => { + let page = i + 1; + let route; + if (page === 1) { + route = '/blog'; + } else { + route = `/blog/page/${page}`; + } + blogPagesRoutes[route] = { + component: `PageBlogPage${page}`, + bundle: { + asset: `/blog/page/${page}.js`, + module: `__blog-page-${page}__`, + }, + }; + + for (let post of pagePosts) { + blogPostRoutes[`/blog/${post.queryPath}`] = { + component: post.componentName, + bundle: { + asset: `/blog/${post.queryPath}.js`, + module: `__blog-${post.queryPath}__`, + }, + parentBundle: { + asset: `/blog/page/${page}.js`, + }, + }; + } + }); + let routes = { + ...blogPagesRoutes, ...blogPostRoutes, ...blogAuthorsRoutes, '/': { component: 'PageHomepage' }, '/404': { component: 'Page404' }, - '/blog': { component: 'PageBlog', bundle: { asset: '/blog.js', module: '__blog__' } }, '/calendar': { component: 'PageCalendar', bundle: { asset: '/calendar.js', module: '__calendar__' }, diff --git a/ember-cli-build.js b/ember-cli-build.js index 80ba63ff3f..20ff435bd9 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -69,10 +69,8 @@ class SimplabsApp extends GlimmerApp { } package(jsTree) { - let [blogTree, mainSiteTree] = this._splitBundle(jsTree, { + let mainSiteTree = this._dropBundle(jsTree, { componentPrefix: 'PageBlog', - file: 'blog.js', - moduleName: '__blog__', }); let { posts, authors } = collectPosts(path.join(__dirname, '_posts')); @@ -84,6 +82,7 @@ class SimplabsApp extends GlimmerApp { }); return blogPostTree; }); + let blogAuthorTrees = authors.map(author => { let [blogAuthorTree] = this._splitBundle(jsTree, { componentPrefix: author.componentName, @@ -93,6 +92,18 @@ class SimplabsApp extends GlimmerApp { return blogAuthorTree; }); + let blogPages = _.chunk(posts, 10); + let blogPageTrees = blogPages.map((posts, i) => { + let page = i + 1; + let postPrefixes = posts.map(post => post.componentName).join('|'); + let [blogPageTree] = this._splitBundle(jsTree, { + componentPrefix: `PageBlogPage${page}|${postPrefixes}`, + file: `blog/page/${page}.js`, + moduleName: `__blog-page-${page}__`, + }); + return blogPageTree; + }); + let [calendarTree, mainSiteNonCalendarTree] = this._splitBundle(mainSiteTree, { componentPrefix: 'PageCalendar', file: 'calendar.js', @@ -136,9 +147,9 @@ class SimplabsApp extends GlimmerApp { playbookTree, talksTree, recentContentTree, - blogTree, ...blogPostTrees, ...blogAuthorTrees, + ...blogPageTrees, ]); if (process.env.PRERENDER) { @@ -177,14 +188,7 @@ class SimplabsApp extends GlimmerApp { } _splitBundle(appTree, bundle) { - let mainBundleTree = new Funnel(appTree, { - exclude: [`src/ui/components/${bundle.componentPrefix}*`], - }); - let mainBundleJsTree = new Funnel(mainBundleTree, { - include: ['**/*.js'], - }); - let mainBundleModuleMap = this.buildResolutionMap(mainBundleJsTree); - mainBundleTree = new MergeTrees([mainBundleTree, mainBundleModuleMap], { overwrite: true }); + let mainBundleTree = this._dropBundle(appTree, bundle); let bundleTree = new Funnel(appTree, { exclude: [`src/ui/components/!(${bundle.componentPrefix})*`], @@ -199,6 +203,17 @@ class SimplabsApp extends GlimmerApp { return [bundleTree, mainBundleTree]; } + _dropBundle(appTree, bundle) { + let mainBundleTree = new Funnel(appTree, { + exclude: [`src/ui/components/+(${bundle.componentPrefix})*`], + }); + let mainBundleJsTree = new Funnel(mainBundleTree, { + include: ['**/*.js'], + }); + let mainBundleModuleMap = this.buildResolutionMap(mainBundleJsTree); + return new MergeTrees([mainBundleTree, mainBundleModuleMap], { overwrite: true }); + } + _packageSplitBundle(bundleTree, bundle) { return new Rollup(bundleTree, { rollup: { diff --git a/lib/generate-blog/lib/collect-posts.js b/lib/generate-blog/lib/collect-posts.js index 8b663f17f3..8b1d9c3558 100644 --- a/lib/generate-blog/lib/collect-posts.js +++ b/lib/generate-blog/lib/collect-posts.js @@ -27,10 +27,12 @@ module.exports = function(folder) { content, }; }); - - let authors = _.chain(posts) + posts = _.chain(posts) .sortBy('meta.date') .reverse() + .value(); + + let authors = _.chain(posts) .uniqBy('meta.twitter') .map(post => { let componentName = buildAuthorComponentName(post); diff --git a/lib/generate-blog/lib/components-builder.js b/lib/generate-blog/lib/components-builder.js index bc1012c3c4..8e2f3c75ce 100644 --- a/lib/generate-blog/lib/components-builder.js +++ b/lib/generate-blog/lib/components-builder.js @@ -41,7 +41,8 @@ module.exports = class ComponentsBuilder extends BaseComponentsBuilder { } writeComponentFiles() { - this._writeStartPageComponent(); + let chunks = _.chunk(this.posts, 10); + chunks.forEach((chunk, i) => this._writeListPageComponent(chunk, i + 1, chunks.length)); for (let post of this.posts) { let related = this._findRelatedPost(post); @@ -58,17 +59,35 @@ module.exports = class ComponentsBuilder extends BaseComponentsBuilder { } } - _writeStartPageComponent() { - let [latest, ...rest] = this.posts; - let data = { - latest: this._preparePostTemplateData(latest), - rest: rest.map(post => this._preparePostTemplateData(post)), + _writeListPageComponent(chunk, page, totalPages) { + let componentName = `PageBlogPage${page}`; + + let data = {}; + let posts = chunk; + if (page === 1) { + let [latest, ...rest] = chunk; + posts = rest; + data.latest = this._preparePostTemplateData(latest); + } + posts = posts.map(post => this._preparePostTemplateData(post)); + + let previousPage = page > 1 ? (page > 2 ? `/blog/page/${page - 1}` : '/blog') : null; + let nextPage = page < totalPages ? `/blog/page/${page + 1}` : null; + + data = { + ...data, + posts, + previousPage, + nextPage, }; - let componentTemplate = this.templates['start-page'].template(data); + let componentTemplate = this.templates['list-page'].template(data); - let componentCssBlock = this.templates['start-page'].stylesheet(); + data = { + componentName, + }; + let componentCssBlock = this.templates['list-page'].stylesheet(data); - this.writeComponent('PageBlog', componentTemplate, componentCssBlock); + this.writeComponent(componentName, componentTemplate, componentCssBlock); } _writePostComponent(post, related) { diff --git a/lib/generate-blog/lib/templates/start-page/stylesheet.hbs b/lib/generate-blog/lib/templates/list-page/stylesheet.hbs similarity index 80% rename from lib/generate-blog/lib/templates/start-page/stylesheet.hbs rename to lib/generate-blog/lib/templates/list-page/stylesheet.hbs index 2888197d05..db717861a5 100644 --- a/lib/generate-blog/lib/templates/start-page/stylesheet.hbs +++ b/lib/generate-blog/lib/templates/list-page/stylesheet.hbs @@ -4,12 +4,13 @@ @block layout from "../../styles/blocks/layout.block.css"; @block offset from "../../styles/blocks/offset.block.css"; @block typography from "../../styles/blocks/typography.block.css"; +@block pagination from '../../styles/blocks/pagination.block.css'; :scope { - block-name: PageBlog; + block-name: {{componentName}}; composes: 'layout'; } .tweet { -} \ No newline at end of file +} diff --git a/lib/generate-blog/lib/templates/start-page/template.hbs b/lib/generate-blog/lib/templates/list-page/template.hbs similarity index 64% rename from lib/generate-blog/lib/templates/start-page/template.hbs rename to lib/generate-blog/lib/templates/list-page/template.hbs index 17f67df877..3e759ca1b3 100644 --- a/lib/generate-blog/lib/templates/start-page/template.hbs +++ b/lib/generate-blog/lib/templates/list-page/template.hbs @@ -36,33 +36,34 @@ > - - - +

+ {{latest.date}} +

+ + Read Post + + + + {{/if}}
- {{#each rest}} + {{#each posts}}
# @@ -84,6 +85,18 @@

{{/each}} +