-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathindex.js
100 lines (87 loc) · 3.64 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const lodash = require('lodash');
const { getAllUniqueKeyValues, slugifyString } = require('../utils');
const site = require('../../src/_data/site');
const { dir } = require('../constants');
/** Returns all blog posts as a collection. */
const getAllPosts = (collection) => {
const posts = collection.getFilteredByGlob(`${dir.input}/_posts/**/*.md`);
return posts.reverse();
};
/** Given a category name and an optional page number, returns the root-relative URL to that category's page.
* @param {string} category
* @param {number} [page] The one-indexed page number
*/
const getCategoryHref = (category, page) => {
const slug = slugifyString(category);
return page > 1 ? `/tags/${slug}/page/${page}/` : `/tags/${slug}/`;
};
/** Returns all unique categories as a collection.
* NOTE: I'm calling these "categories" to distinguish them from 11ty's built-in "tags." However,
* these are still referred to as tags in the UI since that's what's most common.
* @returns {({ title: string; href: string; count: string })[]}
*/
const getAllUniqueCategories = (collection) => {
const allPosts = getAllPosts(collection);
const uniqueCategories = getAllUniqueKeyValues(allPosts, 'categories');
// Do this separately for performance rather than inside the category map logic below, which would be several levels of nesting loops
const categoryCounts = allPosts.reduce((categoryCounts, post) => {
post.data.categories?.forEach((category) => {
if (!categoryCounts[category]) {
categoryCounts[category] = 0;
}
categoryCounts[category]++;
});
return categoryCounts;
}, {});
return (
uniqueCategories
.map((category) => ({
title: category,
href: getCategoryHref(category),
count: categoryCounts[category],
}))
// Popular categories first
.sort((a, b) => b.count - a.count)
);
};
// Blog posts by category, for pagination
// Adapted for use from: https://www.webstoemp.com/blog/basic-custom-taxonomies-with-eleventy/
const getPostsByCategory = (collection) => {
const postsPerPage = site.pagination.itemsPerPage;
const blogPostsByCategory = [];
const allPosts = getAllPosts(collection);
const allUniqueCategories = getAllUniqueKeyValues(allPosts, 'categories');
allUniqueCategories.forEach((category) => {
// Get all posts belonging to this category
const categoryPosts = allPosts.filter((post) => post.data.categories?.includes(category));
// Create a 2D array of chunked posts, where each nested array represents a page.
// e.g., if postsPerPage = 2 and we have three posts, then we'd get [[{post1}, {post2}], [{post3}]]
const chunkedCategoryPosts = lodash.chunk(categoryPosts, postsPerPage);
// Map each chunk to its page slug
const pageHrefs = chunkedCategoryPosts.map((_, pageIndex) => getCategoryHref(category, pageIndex + 1));
chunkedCategoryPosts.forEach((posts, index) => {
// Massage the data into a format that 11ty's pagination will like
// https://github.com/11ty/eleventy/issues/332#issuecomment-445236776
blogPostsByCategory.push({
title: category,
href: pageHrefs[index],
pageNumber: index,
totalPages: pageHrefs.length,
hrefs: {
all: pageHrefs,
next: pageHrefs[index + 1] || null,
previous: pageHrefs[index - 1] || null,
first: pageHrefs[0] || null,
last: pageHrefs[pageHrefs.length - 1] || null,
},
posts,
});
});
});
return blogPostsByCategory.sort((category1, category2) => category2.posts.length - category1.posts.length);
};
module.exports = {
getAllPosts,
getAllUniqueCategories,
getPostsByCategory,
};