From 2ee451f4ca6f185847e244b8584cb4f284fad0d2 Mon Sep 17 00:00:00 2001 From: Peter Meier Date: Sun, 19 Apr 2026 14:18:50 +0200 Subject: [PATCH] feat(post-overview): add excludeTag functionality for filtering posts - Introduced `excludeTag` property in PostOverviewBlockData interface to allow exclusion of specific tag slugs. - Implemented `excludePostsByTagSlugs` function to filter out posts containing specified tag slugs. - Updated `resolvePostOverviewBlocks` function to utilize the new exclusion logic, enhancing post filtering capabilities. --- src/lib/block-types.ts | 2 ++ src/lib/blog-utils.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/lib/block-types.ts b/src/lib/block-types.ts index 13b274e..ec0e2e9 100644 --- a/src/lib/block-types.ts +++ b/src/lib/block-types.ts @@ -182,6 +182,8 @@ export interface PostOverviewBlockData { posts?: unknown[]; /** Tag-Slugs, nach denen gefiltert wird (nur bei allPosts true). */ filterByTag?: string[]; + /** Tag-Slugs, die ausgeschlossen werden (optional, nach filterByTag angewendet). */ + excludeTag?: string[]; /** Max. Anzahl Einträge. */ numberItems?: number; /** "list" | "cards". */ diff --git a/src/lib/blog-utils.ts b/src/lib/blog-utils.ts index 9d92819..5e0dbc9 100644 --- a/src/lib/blog-utils.ts +++ b/src/lib/blog-utils.ts @@ -164,6 +164,21 @@ export function filterPostsByTagSlugs( }); } +/** Filtert Posts: entfernt solche, die mindestens einen der Tag-Slugs haben. */ +export function excludePostsByTagSlugs( + posts: PostEntry[], + tagSlugs: string[], +): PostEntry[] { + if (!tagSlugs?.length) return posts; + return posts.filter((p) => { + const tags = p.postTag ?? []; + return !tags.some((t) => { + const slug = typeof t === "string" ? t : (t as { _slug?: string })?._slug; + return tagSlugs.includes(slug ?? ""); + }); + }); +} + export function getTotalPages(count: number, perPage: number): number { return Math.max(1, Math.ceil(count / perPage)); } @@ -347,6 +362,7 @@ function isPostOverviewBlock(item: unknown): item is { allPosts?: boolean; posts?: unknown[]; filterByTag?: unknown[]; + excludeTag?: unknown[]; numberItems?: number; postsResolved?: unknown[]; } { @@ -389,6 +405,16 @@ export async function resolvePostOverviewBlocks( ) .filter(Boolean) : []; + const rawExclude = item.excludeTag ?? []; + const excludeSlugs = Array.isArray(rawExclude) + ? rawExclude + .map((t) => + typeof t === "string" + ? t + : ((t as { _slug?: string })?._slug ?? ""), + ) + .filter(Boolean) + : []; const hasExplicitPosts = Array.isArray(item.posts) && item.posts.length > 0; const useAllPosts = item.allPosts || (tagSlugs.length > 0 && !hasExplicitPosts); if (useAllPosts) { @@ -400,6 +426,7 @@ export async function resolvePostOverviewBlocks( }); let list = filterHiddenPosts(sortPostsByDate(allPosts)); if (tagSlugs.length) list = filterPostsByTagSlugs(list, tagSlugs); + if (excludeSlugs.length) list = excludePostsByTagSlugs(list, excludeSlugs); const limit = typeof item.numberItems === "number" ? item.numberItems : 9999; item.postsResolved = list.slice(0, limit);