feat(listings): hide unlisted posts from blog and notes
This commit is contained in:
8
blog.njk
8
blog.njk
@@ -3,7 +3,7 @@ layout: layouts/base.njk
|
|||||||
title: Blog
|
title: Blog
|
||||||
withSidebar: true
|
withSidebar: true
|
||||||
pagination:
|
pagination:
|
||||||
data: collections.posts
|
data: collections.listedPosts
|
||||||
size: 20
|
size: 20
|
||||||
alias: paginatedPosts
|
alias: paginatedPosts
|
||||||
permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber + 1 }}/{% endif %}"
|
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="h-feed">
|
||||||
<div class="flex flex-wrap items-center gap-4 mb-2">
|
<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>
|
<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 %}
|
{% if sparklineSvg %}
|
||||||
<div class="flex-1 min-w-0 text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</div>
|
<div class="flex-1 min-w-0 text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
||||||
All posts including articles and notes.
|
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>
|
</p>
|
||||||
|
|
||||||
{% if paginatedPosts.length > 0 %}
|
{% if paginatedPosts.length > 0 %}
|
||||||
<nav class="flex flex-wrap gap-2 mb-6" aria-label="Filter by post type">
|
<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 %}
|
{% for pt in enabledPostTypes %}
|
||||||
{% set collName = pt.label | lower %}
|
{% 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>
|
<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>
|
||||||
|
|||||||
@@ -876,20 +876,23 @@ export default function (eleventyConfig) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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";
|
||||||
|
};
|
||||||
|
|
||||||
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
|
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
|
||||||
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
|
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
|
||||||
if (!Array.isArray(posts)) return [];
|
if (!Array.isArray(posts)) return [];
|
||||||
return posts.filter((post) => {
|
return posts.filter(isListed);
|
||||||
const data = post?.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;
|
|
||||||
|
|
||||||
// Collections for different post types
|
// Collections for different post types
|
||||||
// Note: content path is content/ due to symlink structure
|
// Note: content path is content/ due to symlink structure
|
||||||
// "posts" shows ALL content types combined
|
// "posts" shows ALL content types combined
|
||||||
@@ -900,6 +903,13 @@ export default function (eleventyConfig) {
|
|||||||
.sort((a, b) => b.date - a.date);
|
.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) {
|
eleventyConfig.addCollection("notes", function (collectionApi) {
|
||||||
return collectionApi
|
return collectionApi
|
||||||
.getFilteredByGlob("content/notes/**/*.md")
|
.getFilteredByGlob("content/notes/**/*.md")
|
||||||
@@ -907,6 +917,13 @@ export default function (eleventyConfig) {
|
|||||||
.sort((a, b) => b.date - a.date);
|
.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) {
|
eleventyConfig.addCollection("articles", function (collectionApi) {
|
||||||
return collectionApi
|
return collectionApi
|
||||||
.getFilteredByGlob("content/articles/**/*.md")
|
.getFilteredByGlob("content/articles/**/*.md")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ layout: layouts/base.njk
|
|||||||
title: Notes
|
title: Notes
|
||||||
withSidebar: true
|
withSidebar: true
|
||||||
pagination:
|
pagination:
|
||||||
data: collections.notes
|
data: collections.listedNotes
|
||||||
size: 20
|
size: 20
|
||||||
alias: paginatedNotes
|
alias: paginatedNotes
|
||||||
generatePageOnEmptyData: true
|
generatePageOnEmptyData: true
|
||||||
@@ -12,14 +12,14 @@ permalink: "notes/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumbe
|
|||||||
<div class="h-feed">
|
<div class="h-feed">
|
||||||
<div class="flex flex-wrap items-center gap-4 mb-2">
|
<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>
|
<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 %}
|
{% if sparklineSvg %}
|
||||||
<div class="flex-1 min-w-0 text-teal-600 dark:text-teal-400">{{ sparklineSvg | safe }}</div>
|
<div class="flex-1 min-w-0 text-teal-600 dark:text-teal-400">{{ sparklineSvg | safe }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
||||||
Short thoughts, updates, and quick posts.
|
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>
|
</p>
|
||||||
|
|
||||||
{% if paginatedNotes.length > 0 %}
|
{% if paginatedNotes.length > 0 %}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ layout: layouts/base.njk
|
|||||||
title: Blog
|
title: Blog
|
||||||
withSidebar: true
|
withSidebar: true
|
||||||
pagination:
|
pagination:
|
||||||
data: collections.posts
|
data: collections.listedPosts
|
||||||
size: 20
|
size: 20
|
||||||
alias: paginatedPosts
|
alias: paginatedPosts
|
||||||
permalink: "blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber + 1 }}/{% endif %}"
|
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="h-feed">
|
||||||
<div class="flex flex-wrap items-center gap-4 mb-2">
|
<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>
|
<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 %}
|
{% if sparklineSvg %}
|
||||||
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
|
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
||||||
All posts including articles and notes.
|
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>
|
</p>
|
||||||
|
|
||||||
{% if paginatedPosts.length > 0 %}
|
{% if paginatedPosts.length > 0 %}
|
||||||
|
|||||||
@@ -818,20 +818,23 @@ export default function (eleventyConfig) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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";
|
||||||
|
};
|
||||||
|
|
||||||
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
|
// Exclude unlisted posts from UI slices like homepage/sidebar recent-post lists.
|
||||||
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
|
eleventyConfig.addFilter("excludeUnlistedPosts", (posts) => {
|
||||||
if (!Array.isArray(posts)) return [];
|
if (!Array.isArray(posts)) return [];
|
||||||
return posts.filter((post) => {
|
return posts.filter(isListed);
|
||||||
const data = post?.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;
|
|
||||||
|
|
||||||
// Collections for different post types
|
// Collections for different post types
|
||||||
// Note: content path is content/ due to symlink structure
|
// Note: content path is content/ due to symlink structure
|
||||||
// "posts" shows ALL content types combined
|
// "posts" shows ALL content types combined
|
||||||
@@ -842,6 +845,13 @@ export default function (eleventyConfig) {
|
|||||||
.sort((a, b) => b.date - a.date);
|
.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) {
|
eleventyConfig.addCollection("notes", function (collectionApi) {
|
||||||
return collectionApi
|
return collectionApi
|
||||||
.getFilteredByGlob("content/notes/**/*.md")
|
.getFilteredByGlob("content/notes/**/*.md")
|
||||||
@@ -849,6 +859,13 @@ export default function (eleventyConfig) {
|
|||||||
.sort((a, b) => b.date - a.date);
|
.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) {
|
eleventyConfig.addCollection("articles", function (collectionApi) {
|
||||||
return collectionApi
|
return collectionApi
|
||||||
.getFilteredByGlob("content/articles/**/*.md")
|
.getFilteredByGlob("content/articles/**/*.md")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ layout: layouts/base.njk
|
|||||||
title: Notes
|
title: Notes
|
||||||
withSidebar: true
|
withSidebar: true
|
||||||
pagination:
|
pagination:
|
||||||
data: collections.notes
|
data: collections.listedNotes
|
||||||
size: 20
|
size: 20
|
||||||
alias: paginatedNotes
|
alias: paginatedNotes
|
||||||
generatePageOnEmptyData: true
|
generatePageOnEmptyData: true
|
||||||
@@ -12,14 +12,14 @@ permalink: "notes/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumbe
|
|||||||
<div class="h-feed">
|
<div class="h-feed">
|
||||||
<div class="flex flex-wrap items-center gap-4 mb-2">
|
<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>
|
<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 %}
|
{% if sparklineSvg %}
|
||||||
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
|
<span class="text-amber-600 dark:text-amber-400">{{ sparklineSvg | safe }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
<p class="text-surface-600 dark:text-surface-400 mb-6 sm:mb-8">
|
||||||
Short thoughts, updates, and quick posts.
|
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>
|
</p>
|
||||||
|
|
||||||
{% if paginatedNotes.length > 0 %}
|
{% if paginatedNotes.length > 0 %}
|
||||||
|
|||||||
Reference in New Issue
Block a user