Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
eb8dcd54a8
|
|||
|
030065631c
|
|||
|
5a3e567ed5
|
@ -19,6 +19,11 @@ const geistMono = Geist_Mono({
|
||||
export const metadata: Metadata = {
|
||||
title: "Gaertan Art",
|
||||
description: "Portfolio, Artworks and Commission Requests",
|
||||
alternates: {
|
||||
types: {
|
||||
"application/rss+xml": "/rss.xml",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
71
src/app/rss.xml/route.ts
Normal file
71
src/app/rss.xml/route.ts
Normal 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, "<")
|
||||
.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 [
|
||||
"<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",
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -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({
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user