feat: add weeklyDigests collection for digest feature

- Added weeklyDigests collection after recentPosts collection
- Groups published posts (excluding replies) by ISO 8601 week
- Supports both camelCase and underscore property names
- Includes byType grouping (articles, notes, photos, etc.)
- Calculates week start/end dates for display
- Excludes interactive directory from builds via .eleventyignore
This commit is contained in:
Ricardo
2026-02-25 17:31:43 +01:00
parent abc0404816
commit cd4967f939
2 changed files with 88 additions and 0 deletions

2
.eleventyignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules
interactive

View File

@@ -767,6 +767,92 @@ export default function (eleventyConfig) {
.slice(0, 5); .slice(0, 5);
}); });
// Weekly digests — posts grouped by ISO week for digest pages and RSS feed
eleventyConfig.addCollection("weeklyDigests", function (collectionApi) {
const allPosts = collectionApi
.getFilteredByGlob("content/**/*.md")
.filter(isPublished)
.filter((item) => {
// Exclude replies
return !(item.data.inReplyTo || item.data.in_reply_to);
})
.sort((a, b) => b.date - a.date);
// ISO week helpers
const getISOWeek = (date) => {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
};
const getISOYear = (date) => {
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
return d.getUTCFullYear();
};
// Group by ISO week
const weekMap = new Map();
for (const post of allPosts) {
const d = new Date(post.date);
const week = getISOWeek(d);
const year = getISOYear(d);
const key = `${year}-W${String(week).padStart(2, "0")}`;
if (!weekMap.has(key)) {
// Calculate Monday (start) and Sunday (end) of ISO week
const jan4 = new Date(Date.UTC(year, 0, 4));
const dayOfWeek = jan4.getUTCDay() || 7;
const monday = new Date(jan4);
monday.setUTCDate(jan4.getUTCDate() - dayOfWeek + 1 + (week - 1) * 7);
const sunday = new Date(monday);
sunday.setUTCDate(monday.getUTCDate() + 6);
weekMap.set(key, {
year,
week,
slug: `${year}/W${String(week).padStart(2, "0")}`,
label: `Week ${week}, ${year}`,
startDate: monday.toISOString().slice(0, 10),
endDate: sunday.toISOString().slice(0, 10),
posts: [],
});
}
weekMap.get(key).posts.push(post);
}
// Post type detection (matches blog.njk logic)
const typeDetect = (post) => {
if (post.data.likeOf || post.data.like_of) return "likes";
if (post.data.bookmarkOf || post.data.bookmark_of) return "bookmarks";
if (post.data.repostOf || post.data.repost_of) return "reposts";
if (post.data.photo && post.data.photo.length) return "photos";
if (post.data.title) return "articles";
return "notes";
};
// Build byType for each week and convert to array
const digests = [...weekMap.values()].map((entry) => {
const byType = {};
for (const post of entry.posts) {
const type = typeDetect(post);
if (!byType[type]) byType[type] = [];
byType[type].push(post);
}
return { ...entry, byType };
});
// Sort newest-week-first
digests.sort((a, b) => {
if (a.year !== b.year) return b.year - a.year;
return b.week - a.week;
});
return digests;
});
// Generate OpenGraph images for posts without photos // Generate OpenGraph images for posts without photos
// Runs on every build (including watcher rebuilds) — manifest caching makes it fast // Runs on every build (including watcher rebuilds) — manifest caching makes it fast
// for incremental: only new posts without an OG image get generated (~200ms each) // for incremental: only new posts without an OG image get generated (~200ms each)