Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 17, 2025

Summary

This PR implements a complete blog system for CodeStorm Hub, including blog post infrastructure, author profiles, categories/tags, RSS feed generation, and 5 initial high-quality blog posts covering community announcements, tutorials, and best practices.

Changes Made

Blog Infrastructure

Blog Data System (src/lib/blog-data.ts)

  • Created TypeScript interfaces for BlogPost and Author types
  • Implemented data loading functions for blog posts from markdown files
  • Added frontmatter parsing using gray-matter library
  • Automatic read time calculation based on word count
  • Functions for filtering posts by category, tags, and featured status
  • Author data integration with blog posts

Author Profile System (docs/blog/authors.json)

  • Created 4 author profiles with bios and social media links:
    • CodeStorm Hub Team (Core Team)
    • Syed Salman Reza (Founder & Lead Developer)
    • Development Team (Technical Writers)
    • Community Team (Community Managers)
  • Each author profile includes role, bio, avatar, and social links

Dynamic Blog Pages

Blog Listing Page (src/app/blog/page.tsx)

  • Updated to use dynamic blog data instead of static placeholder content
  • Displays featured posts prominently with special styling
  • Shows recent articles in a grid layout
  • Category filter buttons (All, Announcement, Technical, Community, Tutorial, News)
  • Newsletter signup section
  • RSS feed link for subscribers

Individual Blog Post Page (src/app/blog/[slug]/page.tsx)

  • Dynamic routing for all blog posts
  • Full post content rendering with proper formatting
  • Author profile section with bio and social links
  • Previous/Next post navigation
  • Related posts suggestions (same category)
  • Category and tags display
  • Read time and publication date
  • SEO metadata generation with OpenGraph tags

RSS Feed

RSS Feed Generator (src/app/rss.xml/route.ts)

  • Generates valid RSS 2.0 XML feed
  • Includes all published posts with full metadata
  • Categories and tags included in feed items
  • Proper caching headers for performance
  • Static generation for optimal performance

Layout Update (src/app/layout.tsx)

  • Added RSS feed auto-discovery link to <head> for feed readers

Blog Content

Created 5 comprehensive, well-researched blog posts:

1. Welcome to CodeStorm Hub (Announcement)

  • Introduces the community platform and mission
  • Outlines values: Collaboration, Quality, Inclusivity, Learning, Transparency
  • Explains project portfolio and how to get involved
  • 4,143 characters

2. Our Journey: Building an Open Source Community (Story)

  • Chronicles the founding and growth of CodeStorm Hub
  • Shares lessons learned and challenges overcome
  • Details community values and future vision
  • 8,025 characters

3. Getting Started with Next.js 15 and Radix UI (Technical Tutorial)

  • Comprehensive guide to the tech stack powering CodeStorm Hub
  • Step-by-step setup instructions
  • Code examples for building accessible components
  • Best practices for performance and accessibility
  • 10,335 characters

4. Open Source Best Practices (Educational)

  • Complete guide for contributors and maintainers
  • Covers Git workflows, code review, communication
  • Includes templates for PRs, issues, and documentation
  • Best practices for open-source development
  • 12,034 characters

5. Upcoming Events and Community Roadmap (News)

  • Q4 2025 event schedule with workshops, tech talks, and hackathon
  • Detailed roadmap for project development
  • Community growth initiatives and new features
  • 11,438 characters

Technical Details

  • TypeScript: All code is fully typed with strict mode enabled
  • Build Status: ✅ All 28 pages build successfully including 5 blog post pages
  • Type Check: ✅ Passing
  • Lint: ✅ Passing
  • Performance: Static generation for optimal loading times
  • SEO: Proper metadata and OpenGraph tags on all pages
  • Accessibility: Following WCAG 2.1 AA guidelines

Screenshots

Blog Listing Page

Blog Listing

The blog listing page shows all posts with featured posts highlighted, category filters, newsletter signup, and RSS feed link.

Individual Blog Post Page

Blog Post

Individual post pages display full content with author profiles, navigation, related articles, and metadata.

Testing

  • ✅ Manually tested blog listing page - all posts display correctly
  • ✅ Manually tested all 5 individual blog post pages - content renders properly
  • ✅ Verified RSS feed at /rss.xml - valid XML with all posts
  • ✅ Confirmed category and tag filtering works correctly
  • ✅ Tested previous/next navigation between posts
  • ✅ Verified related posts suggestions display correctly
  • ✅ Build completes successfully with no errors
  • ✅ Type checking passes with strict mode
  • ✅ Linting passes with no warnings

Acceptance Criteria

All acceptance criteria from the issue have been met:

Blog listing and post pages functional - Both working with full dynamic routing
Author profiles and categories/tags present - 4 author profiles, all posts categorized and tagged
RSS feed available - Accessible at /rss.xml with proper formatting
Initial posts published - 5 comprehensive, high-quality blog posts covering diverse topics

References

  • Addresses issue: Implement Blog System and Create Initial Posts
  • Follows guidance from docs/audit-reports/content-improvement-plan.md
  • Implements requirements from docs/audit-reports/implementation-roadmap.md
Original prompt

This section details on the original issue you should resolve

<issue_title>Implement Blog System and Create Initial Posts</issue_title>
<issue_description>## Summary
No blog system or posts exist. Implement a complete blog system with post templates, author profiles, categories/tags, RSS feed, and initial content as outlined in the content improvement plan.

Tasks

  • Set up blog post data structure and template
  • Implement author profile system
  • Add categories/tags to blog posts
  • Implement RSS feed generation
  • Create at least 5 initial posts (welcome, journey, tutorials, guidelines, events)

Acceptance Criteria

  • Blog listing and post pages functional
  • Author profiles and categories/tags present
  • RSS feed available
  • Initial posts published

Priority: High
Deadline: October 28, 2025

References

<agent_instructions>Research and search latest technical, coding, tutorial, best practice, ai related content for the blog and other content. </agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #35


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: syed-reza98 <71028588+syed-reza98@users.noreply.github.com>
{/* Post Navigation */}
<div className="mb-12 flex flex-col sm:flex-row gap-4">
{prevPost && (
<Link href={`/blog/${prevPost.slug}`} className="flex-1">

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.
</Link>
)}
{nextPost && (
<Link href={`/blog/${nextPost.slug}`} className="flex-1">

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

To fix the vulnerability, file names used as slugs should be validated and sanitized before being exposed to the application. This involves ensuring only expected, URL-safe characters are allowed in slugs. The best practice is to implement a function that normalizes slugs, allowing only alphanumeric characters, hyphens, and underscores, and call this function when generating the slug property from file names in getAllBlogPosts(). This change ensures that slugs used in application URLs and rendered into JSX are safe and cannot contain characters leading to XSS.

Required changes:

  • In src/lib/blog-data.ts, create a normalizeSlug function that only allows URL-safe characters.
  • In the mapping over filenames when generating blog posts, apply normalizeSlug to the slug.
  • Make sure the slug used throughout the blog post fetching logic is always normalized.

No changes are required in src/app/blog/[slug]/page.tsx because normalizing at source is sufficient for all downstream consumers.


Suggested changeset 1
src/lib/blog-data.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/blog-data.ts b/src/lib/blog-data.ts
--- a/src/lib/blog-data.ts
+++ b/src/lib/blog-data.ts
@@ -30,9 +30,13 @@
   published?: boolean
 }
 
+// Only allow URL-safe characters in slugs (alphanumeric, -, _)
+function normalizeSlug(filename: string): string {
+  return filename.replace(/\.md$/, '').replace(/[^a-zA-Z0-9-_]/g, '');
+}
+
 let cachedBlogPosts: BlogPost[] | null = null
 let cachedAuthors: Author[] | null = null
-
 export function getAllAuthors(): Author[] {
   if (cachedAuthors !== null) {
     return cachedAuthors
@@ -81,7 +83,7 @@
         const filePath = path.join(blogDir, filename)
         const fileContent = fs.readFileSync(filePath, 'utf8')
         const { data, content } = matter(fileContent)
-        const slug = filename.replace(/\.md$/, '')
+        const slug = normalizeSlug(filename)
         
         // Calculate read time (rough estimate: 200 words per minute)
         const wordCount = content.trim().split(/\s+/).length
EOF
@@ -30,9 +30,13 @@
published?: boolean
}

// Only allow URL-safe characters in slugs (alphanumeric, -, _)
function normalizeSlug(filename: string): string {
return filename.replace(/\.md$/, '').replace(/[^a-zA-Z0-9-_]/g, '');
}

let cachedBlogPosts: BlogPost[] | null = null
let cachedAuthors: Author[] | null = null

export function getAllAuthors(): Author[] {
if (cachedAuthors !== null) {
return cachedAuthors
@@ -81,7 +83,7 @@
const filePath = path.join(blogDir, filename)
const fileContent = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContent)
const slug = filename.replace(/\.md$/, '')
const slug = normalizeSlug(filename)

// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length
Copilot is powered by AI and may make mistakes. Always verify output.
<h2 className="text-2xl font-bold mb-6">Related Articles</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{relatedPosts.map((relatedPost) => (
<Link key={relatedPost.slug} href={`/blog/${relatedPost.slug}`}>

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

The best way to fix this problem is to sanitize or validate slugs at the point where they originate, ensuring that only safe characters are allowed (in particular, allow only URL-safe characters such as [a-zA-Z0-9-_]). This prevents malicious file names from ever being used as slugs or injected into rendered HTML. The solution should be implemented in src/lib/blog-data.ts where blog posts are loaded: filter filenames to ensure they match a safe "slug" pattern before using them to construct blog post objects and inject them downstream. This change only affects the code that turns disk filenames into slugs, preserving the existing functionality while ensuring safety. No changes are necessary to React components that render these values, as making sure tainted slugs cannot propagate is preferable to patching at every usage site.

Changes needed:

  • In src/lib/blog-data.ts, update the logic in getAllBlogPosts to filter out any filenames that, after removing the .md extension, do not conform to a strict slug regex (such as /^[a-zA-Z0-9-_]+$/).
  • This means after line 84, only use slugs that match the required pattern.
  • Optionally, you can define a helper validation function (e.g., isValidSlug).
  • No new external dependencies are needed, as this can be implemented in a few lines of code.

Suggested changeset 1
src/lib/blog-data.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/blog-data.ts b/src/lib/blog-data.ts
--- a/src/lib/blog-data.ts
+++ b/src/lib/blog-data.ts
@@ -75,13 +75,18 @@
 
     const filenames = fs.readdirSync(blogDir)
     
+    // Only include filenames that are .md and give valid slugs
+    const isValidSlug = (slug: string) => /^[a-zA-Z0-9-_]+$/.test(slug)
     cachedBlogPosts = filenames
       .filter(name => name.endsWith('.md'))
       .map(filename => {
+        const slug = filename.replace(/\.md$/, '')
+        if (!isValidSlug(slug)) {
+          return null
+        }
         const filePath = path.join(blogDir, filename)
         const fileContent = fs.readFileSync(filePath, 'utf8')
         const { data, content } = matter(fileContent)
-        const slug = filename.replace(/\.md$/, '')
         
         // Calculate read time (rough estimate: 200 words per minute)
         const wordCount = content.trim().split(/\s+/).length
@@ -110,7 +109,7 @@
 
         return post
       })
-      .filter(post => post.published) // Only return published posts
+      .filter((post): post is BlogPost => !!post && post.published) // Only return published posts with valid slugs
       .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Sort by date, newest first
 
     return cachedBlogPosts
EOF
@@ -75,13 +75,18 @@

const filenames = fs.readdirSync(blogDir)

// Only include filenames that are .md and give valid slugs
const isValidSlug = (slug: string) => /^[a-zA-Z0-9-_]+$/.test(slug)
cachedBlogPosts = filenames
.filter(name => name.endsWith('.md'))
.map(filename => {
const slug = filename.replace(/\.md$/, '')
if (!isValidSlug(slug)) {
return null
}
const filePath = path.join(blogDir, filename)
const fileContent = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContent)
const slug = filename.replace(/\.md$/, '')

// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length
@@ -110,7 +109,7 @@

return post
})
.filter(post => post.published) // Only return published posts
.filter((post): post is BlogPost => !!post && post.published) // Only return published posts with valid slugs
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Sort by date, newest first

return cachedBlogPosts
Copilot is powered by AI and may make mistakes. Always verify output.
<h2 className="text-2xl font-bold mb-6">Related Articles</h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{relatedPosts.map((relatedPost) => (
<Link key={relatedPost.slug} href={`/blog/${relatedPost.slug}`}>

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

The best way to fix the problem is to ensure that slugs derived from file names are sanitized before being used in rendered output. This should be implemented where the slug is defined from the file name, so that all downstream consumers (not just this one Link) get a sanitized version. A simple and effective approach is to only allow "safe" characters in slugs, e.g., alphanumeric, hyphens, and underscores. This can be done by modifying the code that assigns slug in getAllBlogPosts so it replaces or rejects unsafe characters using a regular expression. This way, rendered output in /blog/${slug} always contains safe values. No changes are needed elsewhere.

Implementation details:

  • In src/lib/blog-data.ts, in getAllBlogPosts, after extracting slug from the filename (line 84), apply a sanitation function to remove or replace any disallowed characters.
  • Add a helper function, e.g., sanitizeSlug, that returns only characters allowed in slugs.
  • If you want to be more robust, reject files whose slug cannot be safely sanitized and skip those posts entirely.
  • No package imports are necessary; a local helper function using String.replace is sufficient.
Suggested changeset 1
src/lib/blog-data.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/blog-data.ts b/src/lib/blog-data.ts
--- a/src/lib/blog-data.ts
+++ b/src/lib/blog-data.ts
@@ -81,7 +81,9 @@
         const filePath = path.join(blogDir, filename)
         const fileContent = fs.readFileSync(filePath, 'utf8')
         const { data, content } = matter(fileContent)
-        const slug = filename.replace(/\.md$/, '')
+        // Sanitize slug to include only safe characters (alphanumerics, hyphens, underscores)
+        const unsanitizedSlug = filename.replace(/\.md$/, '')
+        const slug = sanitizeSlug(unsanitizedSlug)
         
         // Calculate read time (rough estimate: 200 words per minute)
         const wordCount = content.trim().split(/\s+/).length
EOF
@@ -81,7 +81,9 @@
const filePath = path.join(blogDir, filename)
const fileContent = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContent)
const slug = filename.replace(/\.md$/, '')
// Sanitize slug to include only safe characters (alphanumerics, hyphens, underscores)
const unsanitizedSlug = filename.replace(/\.md$/, '')
const slug = sanitizeSlug(unsanitizedSlug)

// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length
Copilot is powered by AI and may make mistakes. Always verify output.
</div>
<Button asChild>
<a href={`/blog/${post.slug}`}>
<Link href={`/blog/${post.slug}`}>

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

To fix this vulnerability, we need to sanitize or validate the slug variable before using it in any context where it could generate a URL or HTML attribute from user-controlled input. The best approach is to restrict the slug to a safe subset of characters, such as [a-zA-Z0-9-_]. This can be done in the location where the slug is generated from the filename in getAllBlogPosts() in src/lib/blog-data.ts.
Specifically, after extracting the slug, we should clean it (e.g., via .replace(/[^a-zA-Z0-9-_]/g, "")) to remove any unwanted/unexpected/special characters. This ensures that filenames can't inject problematic values into our URLs or views.

Make the following edits:

  • In src/lib/blog-data.ts, in the code generating the blog post objects, sanitize the computed slug.
  • Optionally, add a utility function for slug sanitization, but only if you don't need to import anything except Node builtins.

Suggested changeset 1
src/lib/blog-data.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/blog-data.ts b/src/lib/blog-data.ts
--- a/src/lib/blog-data.ts
+++ b/src/lib/blog-data.ts
@@ -81,7 +81,8 @@
         const filePath = path.join(blogDir, filename)
         const fileContent = fs.readFileSync(filePath, 'utf8')
         const { data, content } = matter(fileContent)
-        const slug = filename.replace(/\.md$/, '')
+        // Sanitize slug: allow only alphanumeric, dash, and underscore
+        const slug = filename.replace(/\.md$/, '').replace(/[^a-zA-Z0-9-_]/g, '')
         
         // Calculate read time (rough estimate: 200 words per minute)
         const wordCount = content.trim().split(/\s+/).length
EOF
@@ -81,7 +81,8 @@
const filePath = path.join(blogDir, filename)
const fileContent = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContent)
const slug = filename.replace(/\.md$/, '')
// Sanitize slug: allow only alphanumeric, dash, and underscore
const slug = filename.replace(/\.md$/, '').replace(/[^a-zA-Z0-9-_]/g, '')

// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length
Copilot is powered by AI and may make mistakes. Always verify output.
</div>
<Button variant="outline" size="sm" asChild>
<a href={`/blog/${post.slug}`}>
<Link href={`/blog/${post.slug}`}>

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

To fix this issue, we must ensure that slugs derived from filenames are sanitized or validated to avoid dangerous characters before they are exposed via the UI or used for routing. The best approach is to sanitize slugs in src/lib/blog-data.ts just after they are extracted from filenames (line 84-ish). We should restrict slugs to a safe subset (e.g., letters, digits, dashes, underscores), replacing or removing any unsafe characters. This guarantees that only expected, harmless slugs ever get rendered or routed. We will define a sanitization function in src/lib/blog-data.ts and apply it to each slug as it's created. No change is needed in src/app/blog/page.tsx because the data at source will already be safe.

Required changes:

  • Add a slug sanitization function to src/lib/blog-data.ts, restricting allowed characters (e.g., /[\w-]+/).
  • Use this sanitization when creating slug in getAllBlogPosts().
  • No new imports required for a simple regex-based function.

Suggested changeset 1
src/lib/blog-data.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/lib/blog-data.ts b/src/lib/blog-data.ts
--- a/src/lib/blog-data.ts
+++ b/src/lib/blog-data.ts
@@ -30,6 +30,13 @@
   published?: boolean
 }
 
+
+// Remove all but alphanumeric, dash, and underscore from slug.
+function sanitizeSlug(rawSlug: string): string {
+  // Allow a-z, A-Z, 0-9, dash, underscore only. Remove other chars.
+  return rawSlug.replace(/[^a-zA-Z0-9-_]/g, '')
+}
+
 let cachedBlogPosts: BlogPost[] | null = null
 let cachedAuthors: Author[] | null = null
 
@@ -81,7 +88,7 @@
         const filePath = path.join(blogDir, filename)
         const fileContent = fs.readFileSync(filePath, 'utf8')
         const { data, content } = matter(fileContent)
-        const slug = filename.replace(/\.md$/, '')
+        const slug = sanitizeSlug(filename.replace(/\.md$/, ''))
         
         // Calculate read time (rough estimate: 200 words per minute)
         const wordCount = content.trim().split(/\s+/).length
EOF
@@ -30,6 +30,13 @@
published?: boolean
}


// Remove all but alphanumeric, dash, and underscore from slug.
function sanitizeSlug(rawSlug: string): string {
// Allow a-z, A-Z, 0-9, dash, underscore only. Remove other chars.
return rawSlug.replace(/[^a-zA-Z0-9-_]/g, '')
}

let cachedBlogPosts: BlogPost[] | null = null
let cachedAuthors: Author[] | null = null

@@ -81,7 +88,7 @@
const filePath = path.join(blogDir, filename)
const fileContent = fs.readFileSync(filePath, 'utf8')
const { data, content } = matter(fileContent)
const slug = filename.replace(/\.md$/, '')
const slug = sanitizeSlug(filename.replace(/\.md$/, ''))

// Calculate read time (rough estimate: 200 words per minute)
const wordCount = content.trim().split(/\s+/).length
Copilot is powered by AI and may make mistakes. Always verify output.
</channel>
</rss>`

return new Response(rss, {

Check failure

Code scanning / CodeQL

Stored cross-site scripting High

Stored cross-site scripting vulnerability due to
stored value
.

Copilot Autofix

AI 23 days ago

To resolve this issue, the values that derive from file names (i.e., post.slug) and other tainted fields outputted into XML elements must be properly escaped for XML to prevent any injection of malicious markup. Since this RSS feed returns XML content, we need to contextually escape all untrusted data embedded into XML tags (other than those encapsulated inside CDATA sections).

The best way is to escape the special XML characters (<, >, &, ", ') in each outputted field: slug, category, author, tag, etc. We do not need to escape values inside the CDATA blocks (for title and description, which are already safe by definition), but we do need to escape outside values inserted into tag content and attributes.

Thus, we should:

  1. Add a function to escape XML special characters (using a well-known library like he or via a simple helper).
  2. Apply escaping to each untrusted field (especially post.slug, post.category, post.author, all tags) in the places where they are used to build XML in src/app/rss.xml/route.ts.

Since the code only constructs the XML in that file, we only need to update src/app/rss.xml/route.ts, with a helper function and its application.


Suggested changeset 1
src/app/rss.xml/route.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/app/rss.xml/route.ts b/src/app/rss.xml/route.ts
--- a/src/app/rss.xml/route.ts
+++ b/src/app/rss.xml/route.ts
@@ -20,13 +20,13 @@
         (post) => `
     <item>
       <title><![CDATA[${post.title}]]></title>
-      <link>${siteUrl}/blog/${post.slug}</link>
-      <guid>${siteUrl}/blog/${post.slug}</guid>
+      <link>${siteUrl}/blog/${escapeXml(post.slug)}</link>
+      <guid>${siteUrl}/blog/${escapeXml(post.slug)}</guid>
       <description><![CDATA[${post.description}]]></description>
       <pubDate>${new Date(post.date).toUTCString()}</pubDate>
-      <author>${post.author}</author>
-      <category>${post.category}</category>
-      ${post.tags?.map((tag) => `<category>${tag}</category>`).join("\n      ") || ""}
+      <author>${escapeXml(post.author)}</author>
+      <category>${escapeXml(post.category)}</category>
+      ${post.tags?.map((tag) => `<category>${escapeXml(tag)}</category>`).join("\n      ") || ""}
     </item>`
       )
       .join("")}
EOF
@@ -20,13 +20,13 @@
(post) => `
<item>
<title><![CDATA[${post.title}]]></title>
<link>${siteUrl}/blog/${post.slug}</link>
<guid>${siteUrl}/blog/${post.slug}</guid>
<link>${siteUrl}/blog/${escapeXml(post.slug)}</link>
<guid>${siteUrl}/blog/${escapeXml(post.slug)}</guid>
<description><![CDATA[${post.description}]]></description>
<pubDate>${new Date(post.date).toUTCString()}</pubDate>
<author>${post.author}</author>
<category>${post.category}</category>
${post.tags?.map((tag) => `<category>${tag}</category>`).join("\n ") || ""}
<author>${escapeXml(post.author)}</author>
<category>${escapeXml(post.category)}</category>
${post.tags?.map((tag) => `<category>${escapeXml(tag)}</category>`).join("\n ") || ""}
</item>`
)
.join("")}
Copilot is powered by AI and may make mistakes. Always verify output.
Copilot AI changed the title [WIP] Implement blog system and create initial posts Implement Complete Blog System with 5 Initial Posts, Author Profiles, and RSS Feed Oct 17, 2025
Copilot AI requested a review from syed-reza98 October 17, 2025 08:30
Copilot finished work on behalf of syed-reza98 October 17, 2025 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Blog System and Create Initial Posts

2 participants