3 Commits

Author SHA1 Message Date
eb8dcd54a8 Add rss feed with latest 10 artworks 2026-01-31 12:04:04 +01:00
030065631c Add rss feed with latest 10 artworks 2026-01-31 11:51:30 +01:00
5a3e567ed5 Add rss feed with latest 10 artworks 2026-01-31 11:46:21 +01:00
3 changed files with 101 additions and 4 deletions

View File

@ -19,6 +19,11 @@ const geistMono = Geist_Mono({
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Gaertan Art", title: "Gaertan Art",
description: "Portfolio, Artworks and Commission Requests", description: "Portfolio, Artworks and Commission Requests",
alternates: {
types: {
"application/rss+xml": "/rss.xml",
},
},
}; };
export default function RootLayout({ export default function RootLayout({

71
src/app/rss.xml/route.ts Normal file
View File

@ -0,0 +1,71 @@
import { prisma } from "@/lib/prisma";
const BASE_URL = `${process.env.FEED_URL}`
function escapeXml(value: string): string {
return value
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
}
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 [
"<item>",
`<title>${title}</title>`,
`<link>${link}</link>`,
`<guid isPermaLink="true">${link}</guid>`,
`<description>${description}</description>`,
`<pubDate>${pubDate}</pubDate>`,
"</item>",
].join("");
})
.join("");
const xml = [
'<?xml version="1.0" encoding="UTF-8"?>',
'<rss version="2.0">',
"<channel>",
"<title>Gaertan Art - Latest Artworks</title>",
`<link>${BASE_URL}</link>`,
"<description>Ten newest artworks from Gaertan Art.</description>",
`<lastBuildDate>${lastBuildDate}</lastBuildDate>`,
itemXml,
"</channel>",
"</rss>",
].join("");
return new Response(xml, {
headers: {
"Content-Type": "application/rss+xml; charset=utf-8",
},
});
}

View File

@ -3,12 +3,20 @@ import {
siLinktree, siLinktree,
siMastodon, siMastodon,
siPaypal, siPaypal,
siRss,
siTelegram, siTelegram,
siTwitch, siTwitch,
type SimpleIcon, type SimpleIcon,
} from "simple-icons"; } from "simple-icons";
type SocialKey = "paypal" | "telegram" | "mastodon" | "bluesky" | "linktree" | "twitch"; type SocialKey =
| "paypal"
| "telegram"
| "mastodon"
| "bluesky"
| "linktree"
| "twitch"
| "rss";
const SOCIALS: Record< const SOCIALS: Record<
SocialKey, SocialKey,
@ -43,7 +51,12 @@ const SOCIALS: Record<
label: "Twitch", label: "Twitch",
icon: siTwitch, icon: siTwitch,
href: "https://www.twitch.tv/gaertan_art", href: "https://www.twitch.tv/gaertan_art",
} },
rss: {
label: "RSS",
icon: siRss,
href: `/rss.xml`,
},
}; };
function BrandSvg({ icon }: { icon: SimpleIcon }) { function BrandSvg({ icon }: { icon: SimpleIcon }) {
@ -60,7 +73,15 @@ function BrandSvg({ icon }: { icon: SimpleIcon }) {
} }
export function SocialLinks({ export function SocialLinks({
items = ["paypal", "telegram", "mastodon", "bluesky", "linktree", "twitch"], items = [
"paypal",
"telegram",
"mastodon",
"bluesky",
"linktree",
"twitch",
"rss",
],
size = "md", size = "md",
}: { }: {
items?: SocialKey[]; items?: SocialKey[];