From 5a3e567ed52fabbfc42abc00e15df570b830bc32 Mon Sep 17 00:00:00 2001 From: Citali Date: Sat, 31 Jan 2026 11:46:21 +0100 Subject: [PATCH] Add rss feed with latest 10 artworks --- src/app/head.tsx | 5 +++ src/app/rss.xml/route.ts | 71 ++++++++++++++++++++++++++++++++++ src/components/SocialLinks.tsx | 29 ++++++++++++-- 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/app/head.tsx create mode 100644 src/app/rss.xml/route.ts diff --git a/src/app/head.tsx b/src/app/head.tsx new file mode 100644 index 0000000..def451a --- /dev/null +++ b/src/app/head.tsx @@ -0,0 +1,5 @@ +export default function Head() { + return ( + + ); +} diff --git a/src/app/rss.xml/route.ts b/src/app/rss.xml/route.ts new file mode 100644 index 0000000..806efa9 --- /dev/null +++ b/src/app/rss.xml/route.ts @@ -0,0 +1,71 @@ +import { prisma } from "@/lib/prisma"; + +const BASE_URL = `${process.env.BASE_URL}` + +function escapeXml(value: string): string { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +export async function GET() { + const items = await prisma.artwork.findMany({ + where: { published: true }, + orderBy: { createdAt: "desc" }, + take: 10, + select: { + id: true, + name: true, + description: true, + altText: true, + createdAt: true, + updatedAt: true, + }, + }); + + const lastBuildDate = + items[0]?.updatedAt?.toUTCString() ?? new Date().toUTCString(); + + const itemXml = items + .map((item) => { + const title = escapeXml(item.name || "Artwork"); + const description = escapeXml( + item.description || item.altText || item.name || "Artwork" + ); + const link = `${BASE_URL}/artworks/single/${item.id}`; + const pubDate = item.createdAt.toUTCString(); + + return [ + "", + `${title}`, + `${link}`, + `${link}`, + `${description}`, + `${pubDate}`, + "", + ].join(""); + }) + .join(""); + + const xml = [ + '', + '', + "", + "Gaertan Art - Latest Artworks", + `${BASE_URL}`, + "Ten newest artworks from Gaertan Art.", + `${lastBuildDate}`, + itemXml, + "", + "", + ].join(""); + + return new Response(xml, { + headers: { + "Content-Type": "application/rss+xml; charset=utf-8", + }, + }); +} diff --git a/src/components/SocialLinks.tsx b/src/components/SocialLinks.tsx index 1db36e5..b6a0be9 100644 --- a/src/components/SocialLinks.tsx +++ b/src/components/SocialLinks.tsx @@ -3,12 +3,20 @@ import { siLinktree, siMastodon, siPaypal, + siRss, siTelegram, siTwitch, type SimpleIcon, } from "simple-icons"; -type SocialKey = "paypal" | "telegram" | "mastodon" | "bluesky" | "linktree" | "twitch"; +type SocialKey = + | "paypal" + | "telegram" + | "mastodon" + | "bluesky" + | "linktree" + | "twitch" + | "rss"; const SOCIALS: Record< SocialKey, @@ -43,7 +51,12 @@ const SOCIALS: Record< label: "Twitch", icon: siTwitch, href: "https://www.twitch.tv/gaertan_art", - } + }, + rss: { + label: "RSS", + icon: siRss, + href: "/rss.xml", + }, }; function BrandSvg({ icon }: { icon: SimpleIcon }) { @@ -60,7 +73,15 @@ function BrandSvg({ icon }: { icon: SimpleIcon }) { } export function SocialLinks({ - items = ["paypal", "telegram", "mastodon", "bluesky", "linktree", "twitch"], + items = [ + "paypal", + "telegram", + "mastodon", + "bluesky", + "linktree", + "twitch", + "rss", + ], size = "md", }: { items?: SocialKey[]; @@ -99,4 +120,4 @@ export function SocialLinks({ })} ); -} \ No newline at end of file +}