From 52411f6cb9efc10dd683096b34e5c279a11f7e0a Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Tue, 13 Jan 2026 15:31:19 +0100 Subject: Rework how tags are working and make them native --- src/pages/micro/[...page].astro | 10 +++-- src/pages/micro/rss.xml.ts | 6 ++- src/pages/micro/tags/[tag]/[...page].astro | 71 ------------------------------ src/pages/micro/tags/index.astro | 36 --------------- src/pages/tags/[tag]/[...page].astro | 64 ++++++++++++++++++++------- src/pages/tags/[tag]/rss.xml.ts | 69 +++++++++++++++++++++++++++++ src/pages/tags/index.astro | 24 +++++++++- 7 files changed, 150 insertions(+), 130 deletions(-) delete mode 100644 src/pages/micro/tags/[tag]/[...page].astro delete mode 100644 src/pages/micro/tags/index.astro create mode 100644 src/pages/tags/[tag]/rss.xml.ts (limited to 'src/pages') diff --git a/src/pages/micro/[...page].astro b/src/pages/micro/[...page].astro index 8e7e814..d11d9ce 100644 --- a/src/pages/micro/[...page].astro +++ b/src/pages/micro/[...page].astro @@ -9,8 +9,10 @@ import PageLayout from "@/layouts/Base.astro"; export const getStaticPaths = (async ({ paginate }) => { const MAX_MICRO_PER_PAGE = 10; - // Get only Pleroma posts - const allMicro = await getCollection("micro").catch(() => []); // Fallback to empty array if micro collection fails + // Get only Pleroma posts tagged with "micro" + const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], + ); // Fallback to empty array if micro collection fails // Sort all micro posts const allMicroPosts = allMicro.sort( @@ -52,11 +54,11 @@ const paginationProps = {

Micro - + Browse tags - + RSS feed diff --git a/src/pages/micro/rss.xml.ts b/src/pages/micro/rss.xml.ts index 37d7d39..9356341 100644 --- a/src/pages/micro/rss.xml.ts +++ b/src/pages/micro/rss.xml.ts @@ -4,8 +4,10 @@ import type { APIContext } from "astro"; import { siteConfig } from "@/site.config"; export const GET = async (context: APIContext) => { - // Get only Pleroma posts - const allMicro = await getCollection("micro").catch(() => []); // Fallback to empty array if micro collection fails + // Get only Pleroma posts tagged with "micro" + const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], + ); // Fallback to empty array if micro collection fails // Sort all micro posts const allMicroPosts = allMicro.sort( diff --git a/src/pages/micro/tags/[tag]/[...page].astro b/src/pages/micro/tags/[tag]/[...page].astro deleted file mode 100644 index 3f78663..0000000 --- a/src/pages/micro/tags/[tag]/[...page].astro +++ /dev/null @@ -1,71 +0,0 @@ ---- -import { getCollection } from "astro:content"; -import type { GetStaticPaths, InferGetStaticPropsType } from "astro"; -import { Icon } from "astro-icon/components"; -import Note from "@/components/note/Note.astro"; -import Pagination from "@/components/Paginator.astro"; -import PageLayout from "@/layouts/Base.astro"; -import { getUniqueMicroTags, sortMicroEntries } from "@/utils/micro"; - -export const getStaticPaths = (async ({ paginate }) => { - const allMicroPosts = await getCollection("micro"); - const sortedPosts = sortMicroEntries(allMicroPosts); - const uniqueTags = getUniqueMicroTags(sortedPosts); - - return uniqueTags.flatMap((tag) => { - const postsWithTag = sortedPosts.filter((post) => post.data.tags?.includes(tag)); - return paginate(postsWithTag, { - pageSize: 10, - params: { tag }, - }); - }); -}) satisfies GetStaticPaths; - -type Props = InferGetStaticPropsType; - -const { page } = Astro.props as Props; -const { tag } = Astro.params; - -const meta = { - description: `View all micro posts with the tag - ${tag}`, - title: `Micro posts about ${tag}`, -}; - -const paginationProps = { - ...(page.url.prev && { - prevUrl: { - text: "← Previous Page", - url: page.url.prev, - }, - }), - ...(page.url.next && { - nextUrl: { - text: "Next Page →", - url: page.url.next, - }, - }), -}; ---- - - - -

Micro posts about {tag}

-
    - { - page.data.map((note) => ( -
  • - -
  • - )) - } -
- -
diff --git a/src/pages/micro/tags/index.astro b/src/pages/micro/tags/index.astro deleted file mode 100644 index 8d39b8a..0000000 --- a/src/pages/micro/tags/index.astro +++ /dev/null @@ -1,36 +0,0 @@ ---- -import { getCollection } from "astro:content"; -import PageLayout from "@/layouts/Base.astro"; -import { getUniqueMicroTagsWithCount } from "@/utils/micro"; - -const allMicroPosts = await getCollection("micro"); -const allTags = getUniqueMicroTagsWithCount(allMicroPosts); - -const meta = { - description: "A list of all the topics I've written about in my micro posts", - title: "Micro Tags", -}; ---- - - -

Micro Tags

-
    - { - allTags.map(([tag, val]) => ( -
  • - - #{tag} - - - - {val} Post{val > 1 && "s"} - -
  • - )) - } -
-
diff --git a/src/pages/tags/[tag]/[...page].astro b/src/pages/tags/[tag]/[...page].astro index 1d2cc5d..9556309 100644 --- a/src/pages/tags/[tag]/[...page].astro +++ b/src/pages/tags/[tag]/[...page].astro @@ -1,21 +1,35 @@ --- -import { render } from "astro:content"; +import { getCollection, render } from "astro:content"; import type { GetStaticPaths, InferGetStaticPropsType } from "astro"; import { Icon } from "astro-icon/components"; import PostPreview from "@/components/blog/PostPreview.astro"; +import Note from "@/components/note/Note.astro"; import Pagination from "@/components/Paginator.astro"; import { getAllPosts, getTagMeta, getUniqueTags } from "@/data/post"; import PageLayout from "@/layouts/Base.astro"; import { collectionDateSort } from "@/utils/date"; +import { getUniqueMicroTags } from "@/utils/micro"; export const getStaticPaths = (async ({ paginate }) => { - const allPosts = await getAllPosts(true); // Include archived posts for tag filtering - const sortedPosts = allPosts.sort(collectionDateSort); - const uniqueTags = getUniqueTags(sortedPosts); + const allPosts = await getAllPosts(true, true); // Include archived and micro posts for tag filtering + const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], + ); - return uniqueTags.flatMap((tag) => { - const postsWithTag = sortedPosts.filter((post) => post.data.tags.includes(tag)); - return paginate(postsWithTag, { + // Get unique tags from both collections + const postTags = getUniqueTags(allPosts); + const microTags = getUniqueMicroTags(allMicro); + const allTags = [...new Set([...postTags, ...microTags])]; + + return allTags.flatMap((tag) => { + // Filter posts and micro posts by tag + const postsWithTag = allPosts.filter((post) => post.data.tags.includes(tag)); + const microWithTag = allMicro.filter((micro) => micro.data.tags?.includes(tag)); + + // Combine and sort chronologically + const allItems = [...postsWithTag, ...microWithTag].sort(collectionDateSort); + + return paginate(allItems, { pageSize: 10, params: { tag }, }); @@ -30,9 +44,12 @@ const tagMeta = await getTagMeta(tag); const TagContent = tagMeta ? (await render(tagMeta)).Content : null; +// Capitalize first letter of tag for display +const tagDisplay = tag.charAt(0).toUpperCase() + tag.slice(1); + const meta = { description: tagMeta?.data.description ?? `View all posts with the tag - ${tag}`, - title: tagMeta?.data.title ?? `Posts about ${tag}`, + title: tagMeta?.data.title ?? `${tagDisplay} posts`, }; const paginationProps = { @@ -61,18 +78,35 @@ const paginationProps = {
  • {tag}
  • -

    {tagMeta?.data.title ?? `Posts about ${tag}`}

    -
    +

    + {tagMeta?.data.title ?? `${tagDisplay} posts`} + + RSS feed + +

    +
    {tagMeta?.data.description &&

    {tagMeta.data.description}

    } {TagContent && }
      { - page.data.map((p) => ( -
    • - -
    • - )) + page.data.map((item) => + item.collection === "post" ? ( +
    • + +
    • + ) : ( +
    • + +
    • + ), + ) }
    diff --git a/src/pages/tags/[tag]/rss.xml.ts b/src/pages/tags/[tag]/rss.xml.ts new file mode 100644 index 0000000..3fc8ff3 --- /dev/null +++ b/src/pages/tags/[tag]/rss.xml.ts @@ -0,0 +1,69 @@ +import { getCollection } from "astro:content"; +import rss from "@astrojs/rss"; +import type { APIContext } from "astro"; +import { getAllPosts, getUniqueTags } from "@/data/post"; +import { siteConfig } from "@/site.config"; +import { getUniqueMicroTags } from "@/utils/micro"; + +export async function getStaticPaths() { + // Get all posts (including archived) and micro posts to extract all possible tags + const allPosts = await getAllPosts(true, true); // Include archived and micro + const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], + ); + + // Get unique tags from both collections + const postTags = getUniqueTags(allPosts); + const microTags = getUniqueMicroTags(allMicro); + const allTags = [...new Set([...postTags, ...microTags])]; + + return allTags.map((tag) => ({ + params: { tag }, + })); +} + +export const GET = async (context: APIContext) => { + const { tag } = context.params; + + if (!tag) { + throw new Error("Tag parameter is required"); + } + + // Get posts with this tag (include archived and micro) + const allPosts = await getAllPosts(true, true); + const postsWithTag = allPosts.filter((post) => post.data.tags.includes(tag)); + + // Get micro posts with this tag + const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], + ); + const microWithTag = allMicro.filter((micro) => micro.data.tags?.includes(tag)); + + // Combine and sort chronologically + const allItems = [ + ...postsWithTag.map((post) => ({ + title: post.data.title, + description: post.data.description, + pubDate: post.data.publishDate, + link: `posts/${post.id}/`, + content: undefined, + })), + ...microWithTag.map((micro) => ({ + title: micro.data.title, + description: micro.data.description, + pubDate: micro.data.publishDate, + link: `micro/${micro.id}/`, + content: micro.rendered?.html || micro.body || "", + })), + ].sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime()); + + const site = context.site || import.meta.env.SITE; + + return rss({ + title: `${siteConfig.title} - ${tag}`, + description: `Posts tagged with ${tag}`, + site, + items: allItems, + customData: ``, + }); +}; diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro index 376087f..2c7b07b 100644 --- a/src/pages/tags/index.astro +++ b/src/pages/tags/index.astro @@ -1,9 +1,29 @@ --- +import { getCollection } from "astro:content"; import { getAllPosts, getUniqueTagsWithCount } from "@/data/post"; import PageLayout from "@/layouts/Base.astro"; +import { getUniqueMicroTagsWithCount } from "@/utils/micro"; -const allPostsIncludingArchived = await getAllPosts(true); -const allTags = getUniqueTagsWithCount(allPostsIncludingArchived); +const allPostsIncludingArchived = await getAllPosts(true, true); // Include archived and micro +const allMicro = await getCollection("micro", ({ data }) => data.tags?.includes("micro")).catch( + () => [], +); + +// Get tags with counts from both collections +const postTags = getUniqueTagsWithCount(allPostsIncludingArchived); +const microTags = getUniqueMicroTagsWithCount(allMicro); + +// Merge tags and sum counts +const tagMap = new Map(); +for (const [tag, count] of postTags) { + tagMap.set(tag, count); +} +for (const [tag, count] of microTags) { + tagMap.set(tag, (tagMap.get(tag) || 0) + count); +} + +// Convert back to array and sort by count +const allTags = Array.from(tagMap.entries()).sort((a, b) => b[1] - a[1]); const meta = { description: "A list of all the topics I've written about in my posts", -- cgit v1.2.3