Skip to content

Commit cbeb774

Browse files
add RSS feed
1 parent 7c2d4c8 commit cbeb774

7 files changed

+113
-7
lines changed

build.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ const startTime = process.hrtime();
1717

1818
const componentsBuildList = require('./src/components-build-list');
1919
const componentsBuildIndex = require('./src/components-build-index');
20+
const componentsBuildRSS = require('./src/components-build-rss');
2021
const componentsBuildPages = require('./src/components-build-pages');
2122
const componentsBuildScreenshots = require('./src/components-build-screenshots');
2223

2324
// See src/components-build-defaults for list of options that can be overriden
2425
const options = {
2526
components: {
26-
globPattern: 'src/components/b**/*.html',
27+
// globPattern: 'src/components/article**/*.html',
2728
// frontMatter: {
2829
// bodyClass: 'bg-red',
2930
// screenshot: {
@@ -49,6 +50,7 @@ const options = {
4950
co(function* generator() {
5051
yield componentsBuildList(options); // <- builds temporary components list (JSON)
5152
yield componentsBuildIndex(options); // <- builds index pages (by category & most recent)
53+
yield componentsBuildRSS(options); // <- builds RSS feed
5254
yield componentsBuildPages(options); // <- comment to skip building pages
5355
yield componentsBuildScreenshots(options); // <- comment to skip building screenshots
5456
}).then(() => {

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
"postcss-select": "^2.1.0",
138138
"pretty-hrtime": "^1.0.3",
139139
"remove-html-extension": "0.0.1",
140+
"rss": "^1.2.1",
140141
"s3": "^4.4.0",
141142
"titleize": "^1.0.0",
142143
"tmp": "0.0.31",

src/components-build-defaults.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ const moment = require('moment');
22
const titleize = require('titleize');
33

44
const cleanTitleize = str => titleize(str.replace(/(_|-)/g, ' '));
5+
const creationTimeToYMD = c => moment(c.creationTime).format('YYYY-MM-DD');
56

67
module.exports = {
8+
siteUrl: 'http://tachyons.io', // needed for RSS feed
9+
siteDescription: 'Tachyons. Functional CSS for humans.',
710
// Components
811
components: {
912
globPattern: 'src/components/**/*.html', // source components to process
@@ -21,16 +24,23 @@ module.exports = {
2124
createSectionsBy: 'category', // create a section for each category
2225
showSectionsTOC: true, // show Table of Contents (e.g. categories)
2326
},
24-
recent: { // recent components
27+
mostRecent: { // most recent components
2528
title: 'Recent Components',
2629
path: 'components/recent.html', // target location of recent index
2730
sortAllBy: [['creationTime'], ['desc']], // sort by most recent component first
2831
limitAll: 50, // use the 50 most recent ones
29-
createSectionsBy: c => moment(c.creationTime).format('YYYY-MM-DD'), // group by day
32+
createSectionsBy: creationTimeToYMD, // group by day
3033
prettifySection: v => moment(v).format('LL'), // display as day
3134
showSectionsTOC: false, // no need for Table of Contents
3235
},
3336
},
37+
rss: { // RSS feed
38+
title: 'Tachyons Recent Components',
39+
categories: ['CSS', 'Functional CSS'], // Categories this feed belongs to
40+
ttl: 0, // Number of mins feed can be cached
41+
path: 'components/rss.xml', // target location of feed (sync head.html)
42+
count: 20, // how many in feed
43+
},
3444
page: { // options related to each component page
3545
composeTitle: (category, name) => `${category} | ${name}`, // compose title from cat, name
3646
},

src/components-build-list.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ const getComponents = options => new Promise((resolve, reject) => {
4747
const componentPath = componentPaths[comp_idx];
4848

4949
const firstCommit = yield getComponentFirstCommit(repo, componentPath);
50-
const creationTime = firstCommit.date().getTime();
5150

5251
const componentHtml = fs.readFileSync(componentPath, 'utf8');
5352
const fmParsed = fm.parse(componentHtml);
@@ -87,7 +86,8 @@ const getComponents = options => new Promise((resolve, reject) => {
8786
id,
8887
category,
8988
src: componentPath,
90-
creationTime,
89+
creationTime: firstCommit.date().getTime(),
90+
author: firstCommit.author().toString(),
9191
signature,
9292
page,
9393
screenshot,

src/components-build-rss.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const _ = require('lodash');
2+
const chalk = require('chalk');
3+
const fs = require('fs');
4+
const mkdirp = require('mkdirp');
5+
const path = require('path');
6+
const prettyHrtime = require('pretty-hrtime');
7+
const RSS = require('rss');
8+
9+
const defaults = require('./components-build-defaults');
10+
11+
module.exports = _options => new Promise((resolve, reject) => {
12+
const options = _.merge({}, defaults, _options);
13+
const startTime = process.hrtime();
14+
console.log(chalk.magenta('Working on components RSS feed...'));
15+
if (options.components.tempListPath === undefined ||
16+
!fs.existsSync(options.components.tempListPath)) {
17+
reject('Can not find components list (JSON)');
18+
return;
19+
}
20+
21+
const components = JSON.parse(fs.readFileSync(options.components.tempListPath, 'utf8'));
22+
const recentComponents = _.orderBy(components, ['creationTime'], ['desc'])
23+
.slice(0, options.components.rss.count);
24+
25+
// Create the feed
26+
// See https://github.com/dylang/node-rss
27+
const feedOptions = {
28+
title: options.components.rss.title,
29+
description: options.siteDescription,
30+
feed_url: `${options.siteUrl}/${options.components.rss.path}`,
31+
site_url: options.siteUrl,
32+
categories: options.components.rss.categories,
33+
ttl: options.components.rss.ttl,
34+
};
35+
const feed = new RSS(feedOptions);
36+
37+
// Add feed items
38+
recentComponents.forEach((component) => {
39+
const url = `${options.siteUrl}${component.page.href}`;
40+
const screenshotUrl = `${options.siteUrl}${component.screenshot.href}`;
41+
const description = `
42+
<p>${options.siteDescription}</p>
43+
<a href="${url}"><img src="${screenshotUrl}"></a>
44+
<p><small>Component by ${_.escape(component.author)}</small></p>
45+
`;
46+
feed.item({
47+
title: component.page.title,
48+
description,
49+
url,
50+
guid: `${component.category}:${component.id}`,
51+
categories: options.components.rss.categories,
52+
date: component.creationTime,
53+
author: component.author,
54+
// None of this below appears to work.
55+
// Let's put the screenshot straight in the description.
56+
// enclosure: {
57+
// url: `${options.siteUrl}${component.screenshot.href}`,
58+
// type: 'image/jpeg',
59+
// },
60+
// custom_elements: [{
61+
// 'media:content': [{
62+
// _attr: {
63+
// medium: 'image',
64+
// href: `${options.siteUrl}${component.screenshot.href}`,
65+
// // height: media.height,
66+
// // width: media.width
67+
// },
68+
// }],
69+
// }],
70+
});
71+
});
72+
73+
// Save the feed
74+
mkdirp.sync(path.dirname(options.components.rss.path));
75+
fs.writeFileSync(options.components.rss.path, feed.xml());
76+
console.log('- Created RSS feed:', options.components.rss.path);
77+
78+
const elapsed = process.hrtime(startTime);
79+
console.log(chalk.magenta('Done with components RSS feed!'), chalk.dim(prettyHrtime(elapsed)));
80+
resolve();
81+
}); // return promise

src/templates/head.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
<meta name="author" content="@mrmrs">
44
<meta name="viewport" content="width=device-width, initial-scale=1">
55
<link rel="stylesheet" href="/css/tachyons.min.css">
6-
<style>
6+
<link rel="alternate" type="application/rss+xml" title="RSS Feed for Tachyons Recent Components" href="/components/rss.xml" />
7+
<style>
78
.blue { color: #0074D9; }
89
.bg-blue { background-color: #0074D9; }
910

yarn.lock

+12-1
Original file line numberDiff line numberDiff line change
@@ -3468,7 +3468,7 @@ mime-db@~1.25.0:
34683468
version "1.25.0"
34693469
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392"
34703470

3471-
mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7:
3471+
mime-types@^2.1.12, mime-types@^2.1.7, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7:
34723472
version "2.1.13"
34733473
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88"
34743474
dependencies:
@@ -4807,6 +4807,13 @@ rollup@^0.36.3:
48074807
dependencies:
48084808
source-map-support "^0.4.0"
48094809

4810+
rss@^1.2.1:
4811+
version "1.2.1"
4812+
resolved "https://registry.yarnpkg.com/rss/-/rss-1.2.1.tgz#a52671ea35a73ef969b66026b8a2f0653261bc46"
4813+
dependencies:
4814+
mime-types "^2.1.7"
4815+
xml "^1.0.0"
4816+
48104817
rsvp@^3.0.13, rsvp@^3.0.18:
48114818
version "3.3.3"
48124819
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813"
@@ -6061,6 +6068,10 @@ xml2js@^0.4.5:
60616068
sax ">=0.6.0"
60626069
xmlbuilder "^4.1.0"
60636070

6071+
xml@^1.0.0:
6072+
version "1.0.1"
6073+
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
6074+
60646075
xmlbuilder@0.4.2:
60656076
version "0.4.2"
60666077
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.2.tgz#1776d65f3fdbad470a08d8604cdeb1c4e540ff83"

0 commit comments

Comments
 (0)