feat(listings): hide unlisted posts from blog and notes

This commit is contained in:
svemagie
2026-03-08 16:52:54 +01:00
parent b0c68dc375
commit 182d0fd26e
6 changed files with 65 additions and 31 deletions

View File

@@ -3,7 +3,7 @@ layout: layouts/base.njk
title: Blog
withSidebar: true
pagination:
data: collections.posts
data: collections.listedPosts
size: 20
alias: paginatedPosts
permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber + 1 }}/{% endif %}"
@@ -11,19 +11,19 @@ permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber
<div class="h-feed">
<div class="flex flex-wrap items-center gap-4 mb-2">
<h1 class="text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100">Blog</h1>
{% set sparklineSvg = collections.posts | postingFrequency %}
{% set sparklineSvg = collections.listedPosts | postingFrequency %}
{% if sparklineSvg %}
<div class="flex-1 min-w-0 text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</div>
{% endif %}
</div>
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
All posts including articles and notes.
<span class="text-sm">({{ collections.posts.length }} total)</span>
<span class="text-sm">({{ collections.listedPosts.length }} total)</span>
</p>
{% if paginatedPosts.length > 0 %}
<nav class="flex flex-wrap gap-2 mb-6" aria-label="Filter by post type">
<a href="/blog/" class="px-3 py-1.5 text-sm font-medium rounded-full bg-accent-600 text-white dark:bg-accent-700">All Posts <span class="opacity-75">({{ collections.posts.length }})</span></a>
<a href="/blog/" class="px-3 py-1.5 text-sm font-medium rounded-full bg-accent-600 text-white dark:bg-accent-700">All Posts <span class="opacity-75">({{ collections.listedPosts.length }})</span></a>
{% for pt in enabledPostTypes %}
{% set collName = pt.label | lower %}
<a href="{{ pt.path }}" class="px-3 py-1.5 text-sm font-medium rounded-full bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-300 hover:bg-surface-200 dark:hover:bg-surface-700 border border-surface-200 dark:border-surface-700 transition-colors">{{ pt.label }}{% if collections[collName] %} <span class="text-surface-600 dark:text-surface-400">({{ collections[collName].length }})</span>{% endif %}</a>

View File

@@ -876,19 +876,22 @@ export default function (eleventyConfig) {
};
});
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
if (!Array.isArray(posts)) return [];
return posts.filter((post) => {
const data = post?.data || {};
// Helper: exclude drafts from collections
const isPublished = (item) => !item.data.draft;
// Helper: exclude unlisted visibility from public listing surfaces
const isListed = (item) => {
const data = item?.data || {};
const rawVisibility = data.visibility ?? data.properties?.visibility;
const visibility = Array.isArray(rawVisibility) ? rawVisibility[0] : rawVisibility;
return String(visibility ?? "").toLowerCase() !== "unlisted";
});
});
};
// Helper: exclude drafts from collections
const isPublished = (item) => !item.data.draft;
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
if (!Array.isArray(posts)) return [];
return posts.filter(isListed);
});
// Collections for different post types
// Note: content path is content/ due to symlink structure
@@ -900,6 +903,13 @@ export default function (eleventyConfig) {
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("listedPosts", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/**/*.md")
.filter((item) => isPublished(item) && isListed(item))
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("notes", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/notes/**/*.md")
@@ -907,6 +917,13 @@ export default function (eleventyConfig) {
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("listedNotes", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/notes/**/*.md")
.filter((item) => isPublished(item) && isListed(item))
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("articles", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/articles/**/*.md")

View File

@@ -3,7 +3,7 @@ layout: layouts/base.njk
title: Notes
withSidebar: true
pagination:
data: collections.notes
data: collections.listedNotes
size: 20
alias: paginatedNotes
generatePageOnEmptyData: true
@@ -12,14 +12,14 @@ permalink: "notes/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumbe
<div class="h-feed">
<div class="flex flex-wrap items-center gap-4 mb-2">
<h1 class="text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100">Notes</h1>
{% set sparklineSvg = collections.notes | postingFrequency %}
{% set sparklineSvg = collections.listedNotes | postingFrequency %}
{% if sparklineSvg %}
<div class="flex-1 min-w-0 text-teal-600 dark:text-teal-400">{{ sparklineSvg | safe }}</div>
{% endif %}
</div>
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
Short thoughts, updates, and quick posts.
<span class="text-sm">({{ collections.notes.length }} total)</span>
<span class="text-sm">({{ collections.listedNotes.length }} total)</span>
</p>
{% if paginatedNotes.length > 0 %}

View File

@@ -3,7 +3,7 @@ layout: layouts/base.njk
title: Blog
withSidebar: true
pagination:
data: collections.posts
data: collections.listedPosts
size: 20
alias: paginatedPosts
permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber + 1 }}/{% endif %}"
@@ -11,14 +11,14 @@ permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber
<div class="h-feed">
<div class="flex flex-wrap items-center gap-4 mb-2">
<h1 class="text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100">Blog</h1>
{% set sparklineSvg = collections.posts | postingFrequency %}
{% set sparklineSvg = collections.listedPosts | postingFrequency %}
{% if sparklineSvg %}
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
{% endif %}
</div>
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
All posts including articles and notes.
<span class="text-sm">({{ collections.posts.length }} total)</span>
<span class="text-sm">({{ collections.listedPosts.length }} total)</span>
</p>
{% if paginatedPosts.length > 0 %}

View File

@@ -818,19 +818,22 @@ export default function (eleventyConfig) {
};
});
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
if (!Array.isArray(posts)) return [];
return posts.filter((post) => {
const data = post?.data || {};
// Helper: exclude drafts from collections
const isPublished = (item) => !item.data.draft;
// Helper: exclude unlisted visibility from public listing surfaces
const isListed = (item) => {
const data = item?.data || {};
const rawVisibility = data.visibility ?? data.properties?.visibility;
const visibility = Array.isArray(rawVisibility) ? rawVisibility[0] : rawVisibility;
return String(visibility ?? "").toLowerCase() !== "unlisted";
});
});
};
// Helper: exclude drafts from collections
const isPublished = (item) => !item.data.draft;
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
if (!Array.isArray(posts)) return [];
return posts.filter(isListed);
});
// Collections for different post types
// Note: content path is content/ due to symlink structure
@@ -842,6 +845,13 @@ export default function (eleventyConfig) {
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("listedPosts", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/**/*.md")
.filter((item) => isPublished(item) && isListed(item))
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("notes", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/notes/**/*.md")
@@ -849,6 +859,13 @@ export default function (eleventyConfig) {
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("listedNotes", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/notes/**/*.md")
.filter((item) => isPublished(item) && isListed(item))
.sort((a, b) => b.date - a.date);
});
eleventyConfig.addCollection("articles", function (collectionApi) {
return collectionApi
.getFilteredByGlob("content/articles/**/*.md")

View File

@@ -3,7 +3,7 @@ layout: layouts/base.njk
title: Notes
withSidebar: true
pagination:
data: collections.notes
data: collections.listedNotes
size: 20
alias: paginatedNotes
generatePageOnEmptyData: true
@@ -12,14 +12,14 @@ permalink: "notes/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumbe
<div class="h-feed">
<div class="flex flex-wrap items-center gap-4 mb-2">
<h1 class="text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100">Notes</h1>
{% set sparklineSvg = collections.notes | postingFrequency %}
{% set sparklineSvg = collections.listedNotes | postingFrequency %}
{% if sparklineSvg %}
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
{% endif %}
</div>
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
Short thoughts, updates, and quick posts.
<span class="text-sm">({{ collections.notes.length }} total)</span>
<span class="text-sm">({{ collections.listedNotes.length }} total)</span>
</p>
{% if paginatedNotes.length > 0 %}