Skip to content

Commit

Permalink
Add RSS feed to the blog (#16)
Browse files Browse the repository at this point in the history
* Add RSS feed to the blog
* Include rss link in the head for the blog page
* Include RSS icon and link in the footer
* Fix base url for preview
  • Loading branch information
conradolandia authored Sep 19, 2024
1 parent fbf38a2 commit ff3fcf8
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/lib/blocks/Blog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

<svelte:head>
<link rel="canonical" href={url} />
<link rel="alternate" type="application/rss+xml" title="Spyder's Blog" href="{url}/feed.xml">
</svelte:head>

<div class="container">
Expand Down
18 changes: 9 additions & 9 deletions src/lib/blocks/Footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

<!-- Footer -->
<footer
class="relative
mt-28
pb-14
text-md
text-center
text-mine-shaft-500
dark:text-mine-shaft-300
bg-quill-gray-200
dark:bg-mine-shaft-900"
class="relative
mt-28
pb-14
text-md
text-center
text-mine-shaft-500
dark:text-mine-shaft-300
bg-quill-gray-200
dark:bg-mine-shaft-900"
>
<Divider />
<div class="container mt-14">
Expand Down
2 changes: 2 additions & 0 deletions src/lib/components/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
BsApple,
BsQuestionCircleFill,
BsDownload,
BsRssFill,
} from "svelte-icons-pack/bs";
import { VscTerminalLinux } from "svelte-icons-pack/vsc";
Expand All @@ -25,6 +26,7 @@
mac: BsApple,
unknown: BsQuestionCircleFill,
download: BsDownload,
rss: BsRssFill,
};
export let button = true;
Expand Down
1 change: 1 addition & 0 deletions src/lib/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const socials = {
facebook: "https://www.facebook.com/SpyderIDE/",
mastodon: "https://fosstodon.org/@Spyder",
instagram: "https://instagram.com/spyderide",
rss: `${base}/blog/feed.xml`
};

// Hero content
Expand Down
14 changes: 8 additions & 6 deletions src/lib/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { browser } from "$app/environment";

// Fetch all blog posts
// Determine if a variable has a value (even `false` or `0`)
export const hasValue = (a) => a !== undefined && a !== null;

// Fetch all blog posts, sorted by date, optionally paginated
export const fetchMarkdownPosts = async (pageNum, pageSize) => {
// Load all posts
const allPostFiles = import.meta.glob("/src/routes/blog/**/*.md", {
eager: true,
});

// Convert the object into an array
const iterablePostFiles = Object.entries(allPostFiles);

// Create an array of posts
const allPosts = iterablePostFiles.map(([path, module]) => {
const allPosts = Object.entries(allPostFiles).map(([path, module]) => {
// Get the metadata from the module
const { metadata } = module;

// Format the path to get the slug
const segments = path.split("/");
segments.pop();
Expand All @@ -30,6 +29,9 @@ export const fetchMarkdownPosts = async (pageNum, pageSize) => {
// Sort posts
const sortedPosts = sortPostsByDate(allPosts);

// If we don't provide a page number/page size, return the full list
if (!hasValue(pageNum) || !hasValue(pageSize)) return sortedPosts;

// Calculate start and end indices for the desired page
const start = (pageNum - 1) * pageSize;
const end = start + pageSize;
Expand Down
42 changes: 42 additions & 0 deletions src/routes/blog/feed.xml/+server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { fetchMarkdownPosts } from "$lib/utils";
import { siteUrl, blogTitle, description, comment } from "$lib/config";

export async function GET() {
const posts = await fetchMarkdownPosts();

if (!Array.isArray(posts) || posts.length === 0) {
console.error('No posts found or invalid posts data');
return new Response('Error generating RSS feed', { status: 500 });
}

const feedItems = posts.map(post => `
<item>
<title>${post.meta.title}</title>
<link>${siteUrl}blog/${post.path}</link>
<description>${post.meta.summary || ''}</description>
<category>${post.meta.category || ''}</category>
<pubDate>${new Date(post.meta.pub_date).toUTCString()}</pubDate>
</item>
`).join('');

const rss = `
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>${blogTitle}</title>
<link>${siteUrl}blog</link>
<description>${description} | ${comment}</description>
<atom:link href="${siteUrl}blog/feed.xml" rel="self" type="application/rss+xml"/>
${feedItems}
</channel>
</rss>
`.trim();

return new Response(rss, {
headers: {
'Content-Type': 'application/xml',
},
});
}

export const prerender = true

0 comments on commit ff3fcf8

Please sign in to comment.