diff --git a/app/blog.rss/route.ts b/app/blog.rss/route.ts new file mode 100644 index 0000000..753acb6 --- /dev/null +++ b/app/blog.rss/route.ts @@ -0,0 +1,65 @@ +import { allPosts, Post } from "content-collections"; +import { compareDesc, parseISO, setHours } from "date-fns"; +import { Feed } from "feed"; + +const baseUrl = "https://techaro.lol"; + +const createPostUrl = (url: string) => { + return url + "?utm_campaign=feed&utm_source=blog.rss"; +}; + +const createContent = (post: Post, url: string) => ` +
${post.summary}
+Read the full article on techaro.lol
`; + +const createFeed = () => { + const feed = new Feed({ + title: "Techaro Blog", + description: "Insights and updates from the Techaro team.", + id: baseUrl, + link: baseUrl, + language: "en", + favicon: `${baseUrl}/favicon.ico`, + copyright: `All rights reserved ${new Date().getFullYear()}, Techaro Computing Canada`, + author: { + name: "Techaro Staff", + email: "staff@techaro.lol", + link: baseUrl, + }, + }); + + allPosts + .sort((a, b) => compareDesc(new Date(a.date), new Date(b.date))) + .forEach((post) => { + const id = `${baseUrl}/${post.urlPath}`; + const url = createPostUrl(id); + feed.addItem({ + title: post.title, + id: id, + link: url, + description: post.summary, + content: createContent(post, url), + author: [ + { + name: post.author!.displayName!, + email: `${post.author?.name}@techaro.lol`, + link: baseUrl, + } + ], + date: setHours(parseISO(post.date), 13), + image: post.imageURL, + }); + }); + + return feed.rss2(); +}; + +export const GET = async () => { + const feed = await createFeed(); + return new Response(feed, { + status: 200, + headers: { + "Content-Type": "application/xml", + }, + }); +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1df24a3..7f1b10a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@arcjet/next": "^1.0.0-alpha.26", "@tabler/icons-react": "^3.17.0", + "date-fns": "^4.1.0", + "feed": "^4.2.2", "lucide-react": "^0.399.0", "next": "^14.2.11", "react": "^18.3.1", @@ -3044,6 +3046,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -4207,6 +4219,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/figures": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", @@ -7870,6 +7894,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -9176,6 +9206,18 @@ "dev": true, "license": "ISC" }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 9065186..b00f7db 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "dependencies": { "@arcjet/next": "^1.0.0-alpha.26", "@tabler/icons-react": "^3.17.0", + "date-fns": "^4.1.0", + "feed": "^4.2.2", "lucide-react": "^0.399.0", "next": "^14.2.11", "react": "^18.3.1", diff --git a/tsconfig.json b/tsconfig.json index 310b71c..e415a30 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,12 @@ "content-collections": ["./.content-collections/generated"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "scripts/generate-rss-feed.mjs" + ], "exclude": ["node_modules"] }