feat: initial release of pengzhan.dev personal editorial blog platform
- Editorial web platform built with Node.js, Express, EJS, and Vanilla CSS - Markdown content engine with YAML frontmatter, bilingual variants, and hot-reload watcher - Unified SQLite with FTS5 search indexing, query logging, and schema filters - Centered editorial post layout with margin-docked left TOC and mobile bottom sheet - WordPress-grade comment system with moderation dashboard and bulk operations under /guanli - Complete SEO suite (JSON-LD structured data, RSS/Atom feeds, XML sitemap, robots.txt) - CI/CD workflows for linting, security audits (Gitleaks), automated tests, and Docker releases
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { Feed } = require('feed');
|
||||
const contentService = require('../services/content');
|
||||
|
||||
function generateFeed(site) {
|
||||
const feed = new Feed({
|
||||
title: site.title,
|
||||
description: site.tagline,
|
||||
id: site.url,
|
||||
link: site.url,
|
||||
language: 'en',
|
||||
image: `${site.url}/images/og-default.png`,
|
||||
favicon: `${site.url}/favicon.ico`,
|
||||
copyright: `All rights reserved ${new Date().getFullYear()}, ${site.author ? site.author.name : site.title}`,
|
||||
author: {
|
||||
name: site.author ? site.author.name : site.title,
|
||||
link: site.url
|
||||
}
|
||||
});
|
||||
|
||||
const posts = contentService.getAllPosts();
|
||||
|
||||
for (const post of posts) {
|
||||
const postUrl = `${site.url}/${post.slug}`;
|
||||
feed.addItem({
|
||||
title: post.title,
|
||||
id: postUrl,
|
||||
link: postUrl,
|
||||
description: post.excerpt,
|
||||
content: post.contentHtml,
|
||||
author: [
|
||||
{
|
||||
name: post.author,
|
||||
link: site.url
|
||||
}
|
||||
],
|
||||
date: post.date,
|
||||
image: post.cover ? (post.cover.startsWith('http') ? post.cover : `${site.url}${post.cover}`) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
return feed;
|
||||
}
|
||||
|
||||
router.get(['/feed', '/rss.xml', '/feed.xml'], (req, res) => {
|
||||
const feed = generateFeed(res.locals.site);
|
||||
res.header('Content-Type', 'application/xml; charset=utf-8');
|
||||
res.send(feed.rss2());
|
||||
});
|
||||
|
||||
router.get('/atom.xml', (req, res) => {
|
||||
const feed = generateFeed(res.locals.site);
|
||||
res.header('Content-Type', 'application/atom+xml; charset=utf-8');
|
||||
res.send(feed.atom1());
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user