From bd235967a239f0629ff4ea6371dddfaf6c5cc18f Mon Sep 17 00:00:00 2001 From: Sean Massa Date: Mon, 15 Jan 2024 22:03:23 -0600 Subject: [PATCH] set up rss --- README.md | 2 +- app/styles/app.css | 40 ++++++++++++++------- lib/generate-rss.js | 88 +++++++++++++++++++++++++++++++++++++++++++++ lib/get-articles.js | 24 +++++++++++++ lib/scan-dir.js | 23 ++---------- package.json | 3 +- 6 files changed, 145 insertions(+), 35 deletions(-) create mode 100644 lib/generate-rss.js create mode 100644 lib/get-articles.js diff --git a/README.md b/README.md index 6cdceb8..98faa92 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ ## To Do -- add RSS (so that https://massalabs.com/feed.xml still works) - 404 protection: https://remysharp.com/2023/09/26/no-more-404 - add search: https://pagefind.app/ +- add "callout" component diff --git a/app/styles/app.css b/app/styles/app.css index bc545d1..91ecc25 100644 --- a/app/styles/app.css +++ b/app/styles/app.css @@ -56,26 +56,51 @@ h1, h2, h3 { margin-bottom: 0; } +h1 { + font-size: 2.6rem; + color: var(--accent); +} + +h2 { + font-size: 2.1rem; + color: var(--accent-sub2); +} + +h3 { + font-size: 1.6rem; + color: var(--accent-sub3); +} + h1:has(+ h2), h2:has(+ h3) { margin-bottom: 0; } -h1, h1 a, h1 a:visited { +h1 a, h1 a:visited { color: var(--accent); + /* text-decoration: wavy underline; */ + /* text-decoration-color: #939191; */ } -h2, h2 a, h2 a:visited { +h2 a, h2 a:visited { color: var(--accent-sub2); + /* text-decoration: wavy underline; */ + /* text-decoration-color: #939191; */ } -h3, h3 a, h3 a:visited { +h3 a, h3 a:visited { color: var(--accent-sub3); + /* text-decoration: wavy underline; */ + /* text-decoration-color: #939191; */ } a, a:visited { color:var(--accent); } +a:hover { + text-decoration: underline dotted; +} + header>nav { padding:0; } @@ -133,10 +158,6 @@ footer p a[href^="https://"]:after, padding-right: 1em; /* sizing */ } -.blog-item h2 a { - font-size: 1.6rem; -} - .blog-item h1, .blog-item h2, .blog-item h3 { margin-bottom: 0; margin-top: 0.7em; @@ -160,11 +181,6 @@ footer p a[href^="https://"]:after, display: inline-block; } -.post-link { - font-size: 1.6rem; - font-weight: bold; -} - .meta { color: var(--text-light); font-size: 1rem; diff --git a/lib/generate-rss.js b/lib/generate-rss.js new file mode 100644 index 0000000..3dcc020 --- /dev/null +++ b/lib/generate-rss.js @@ -0,0 +1,88 @@ +let fs = require('node:fs/promises'); +let path = require('node:path'); +let getArticles = require('./get-articles'); + +let siteData = { + title: "Massa Labs", + description: "Sean Massa's personal site where they discuss tech, organizations, ethics, and games.", + url: 'https://massalabs.com' +}; + +// Source: https://stackoverflow.com/a/27979933 +function escapeXml(unsafe) { + return unsafe.replace(/[<>&'"]/g, function (c) { + switch (c) { + case '<': return '<'; + case '>': return '>'; + case '&': return '&'; + case '\'': return '''; + case '"': return '"'; + } + }); +} + +function toUtcDate(str) { + return new Date(Date.parse(str)).toUTCString();; +} + +function generateTags(article) { + // TODO: implement tags + // {{ tag | xml_escape }} + return ''; +} + +function generateRssItem(article) { + let fullUrl = `https://massalabs.com/blog/${article.slug}`; + let tags = generateTags(article); + + return ` + + ${escapeXml(article.title)} + ${escapeXml(article.description)} + ${toUtcDate(article.date)} + ${fullUrl} + ${fullUrl} + ${tags} + + `.trim(); +} + +function generateRss(articles) { + let mostRecentPublishedArticle = articles.find((a) => a.published); + let mostRecentPublishedDate = toUtcDate(mostRecentPublishedArticle.date); + let generationDate = (new Date()).toUTCString(); + let posts = articles.map(a => generateRssItem(a)).join('\n'); + + return ` + + + + ${siteData.title} + ${siteData.description} + ${siteData.url} + + ${generationDate} + ${mostRecentPublishedDate} + ${posts} + + + `.trim(); +} + +async function writeRss() { + let articles = getArticles(); + let rssString = generateRss(articles); + + let pathToRss = path.join(__dirname, '../dist/feed.xml'); + await fs.writeFile(pathToRss, rssString); +} + +writeRss().then(() => { + console.log('Generated rss!') +}).catch((error) => { + console.error('Failed to generate rss!'); + console.error(error); +}); + + + diff --git a/lib/get-articles.js b/lib/get-articles.js new file mode 100644 index 0000000..a0f90c9 --- /dev/null +++ b/lib/get-articles.js @@ -0,0 +1,24 @@ +let fs = require('fs'); +let { join } = require('path'); + +function tryParseJSON(jsonText, originalFilePath) { + try { + return JSON.parse(jsonText); + } catch (error) { + console.log(`JSON Parse Error of "${originalFilePath}": ${error.message}\nText:\n${jsonText}`); + } +} + +module.exports = function getArticles() { + /* + We have to convert the module format into json because no other mechanism for + share this data worked between ember build (node, commonjs) and the + project code (browser, module). + */ + let articlePath = join(__dirname, '/../app/article-data.js'); + let articleData = fs.readFileSync(articlePath).toString(); + let trimmedArticleData = articleData + .replace('let articles =', '') + .replace('export default articles;', ''); + return tryParseJSON(trimmedArticleData, articlePath); +} diff --git a/lib/scan-dir.js b/lib/scan-dir.js index 7307511..d1e73e3 100644 --- a/lib/scan-dir.js +++ b/lib/scan-dir.js @@ -1,26 +1,7 @@ -let fs = require('fs'); -let { join } = require('path'); - -function tryParseJSON(jsonText, originalFilePath) { - try { - return JSON.parse(jsonText); - } catch (error) { - console.log(`JSON Parse Error of "${originalFilePath}": ${error.message}\nText:\n${jsonText}`); - } -} +let getArticles = require('./get-articles'); module.exports = async function ({ distDir, visit }) { - /* - We haev to convert the module format into json because no other mechanism for - share this data worked between ember build (node, commonjs) and the - project code (browser, module). - */ - let articlePath = join(__dirname, '/../app/article-data.js'); - let articleData = fs.readFileSync(articlePath).toString(); - let trimmedArticleData = articleData - .replace('let articles =', '') - .replace('export default articles;', ''); - let articles = tryParseJSON(trimmedArticleData, articlePath); + let articles = getArticles(); let articleUrls = articles.map((a) => { return '/blog/' + a.slug.replace(/\./g, '/'); }); diff --git a/package.json b/package.json index 516c97d..cff0c77 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "test": "tests" }, "scripts": { - "build": "ember build --environment=production", + "gen-rss": "node lib/generate-rss.js", + "build": "ember build --environment=production && npm run gen-rss", "start": "ember serve", "test": "ember test" },