diff --git a/docs/api-site-config.md b/docs/api-site-config.md
index 48076ab85f..bc32b778b3 100644
--- a/docs/api-site-config.md
+++ b/docs/api-site-config.md
@@ -57,6 +57,8 @@ headerLinks: [
- `prismColor` is the color used in the background of syntax highlighting for code in documentation. It is recommended to be the same color as `primaryColor` in `rgba` form with an alpha value of `0.03`. Other fields can be added
- Custom color configurations can also be added. For example, if user styles are added with colors specified as `$myColor`, then adding a `myColor` field to `colors` will allow you to easily configure this color.
+`copyright` - The copyright string at footer of site and within feed
+
### Optional Fields
`editUrl` - url for editing docs, usage example: `editUrl + 'en/doc1.md'`. If this field is omitted, there will be no "Edit this Doc" button for each document.
diff --git a/docs/guides-blog.md b/docs/guides-blog.md
index ea73b0264f..b73f90cfc7 100644
--- a/docs/guides-blog.md
+++ b/docs/guides-blog.md
@@ -67,3 +67,9 @@ Not this.
Or this.
```
+
+## RSS Feed
+
+Docusaurus provides a simple RSS feed for your blog posts. Both RSS and Atom feed formats are supported. This data is automatically to your website page's HTML
tag.
+
+A summary of the post's text is provided in the RSS feed up to the ``. If no `` tag is found, then all text up 250 chacters are used.
\ No newline at end of file
diff --git a/examples/basics/siteConfig.js b/examples/basics/siteConfig.js
index accc9e4abf..96b5cc6b60 100644
--- a/examples/basics/siteConfig.js
+++ b/examples/basics/siteConfig.js
@@ -24,10 +24,10 @@ const siteConfig = {
baseUrl: "/test-site/" /* base url for your project */,
projectName: "test-site",
headerLinks: [
- { doc: "doc1", label: "Docs" },
- { doc: "doc4", label: "API" },
- { page: "help", label: "Help" },
- { blog: true, label: "Blog" }
+ {doc: "doc1", label: "Docs"},
+ {doc: "doc4", label: "API"},
+ {page: "help", label: "Help"},
+ {blog: true, label: "Blog"}
],
users,
/* path to images for header/footer */
@@ -40,7 +40,12 @@ const siteConfig = {
secondaryColor: "#205C3B",
prismColor:
"rgba(46, 133, 85, 0.03)" /* primaryColor in rgba form, with 0.03 alpha */
- }
+ },
+ // This copyright info is used in /core/Footer.js and blog rss/atom feeds.
+ copyright:
+ "Copyright © " +
+ new Date().getFullYear() +
+ " Your Name or Your Company Name"
};
module.exports = siteConfig;
diff --git a/lib/core/Head.js b/lib/core/Head.js
index 983591e6b2..f3edcd030e 100644
--- a/lib/core/Head.js
+++ b/lib/core/Head.js
@@ -12,37 +12,58 @@ const React = require("react");
// html head for each page
class Head extends React.Component {
render() {
+ let links = this.props.config.headerLinks;
+ let hasBlog = false;
+ links.map(link => {
+ if (link.blog) hasBlog = true;
+ });
return (
-
- {this.props.title}
-
+ {this.props.title}
- {this.props.config.ogImage &&
+ {this.props.config.ogImage && (
}
+ />
+ )}
- {this.props.config.algolia &&
+ {this.props.config.algolia && (
}
+ />
+ )}
+ {hasBlog && (
+
+ )}{" "}
+ {hasBlog && (
+
+ )}
);
diff --git a/lib/generate-feed.js b/lib/generate-feed.js
new file mode 100644
index 0000000000..1be58d2afb
--- /dev/null
+++ b/lib/generate-feed.js
@@ -0,0 +1,33 @@
+#!/usr/bin/env node
+
+/**
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+require("babel-register")({
+ babelrc: false,
+ only: [__dirname, process.cwd() + "/core"],
+ plugins: [require("./server/translate-plugin.js")],
+ presets: ["react", "latest"]
+});
+
+// initial check that required files are present
+const chalk = require("chalk");
+const fs = require("fs");
+const CWD = process.cwd();
+
+if (!fs.existsSync(CWD + "/siteConfig.js")) {
+ console.error(
+ chalk.red("Error: No siteConfig.js file found in website folder!")
+ );
+ process.exit(1);
+}
+
+// generate rss feed
+const feed = require("./server/feed.js");
+console.log(feed());
diff --git a/lib/server/feed.js b/lib/server/feed.js
new file mode 100644
index 0000000000..9abf24e423
--- /dev/null
+++ b/lib/server/feed.js
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2017-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+const fs = require("fs-extra");
+const path = require("path");
+const os = require("os");
+const Feed = require("feed");
+
+const chalk = require("chalk");
+const CWD = process.cwd();
+
+const siteConfig = require(CWD + "/siteConfig.js");
+
+const blogFolder = path.resolve("../blog/");
+const blogRootURL = siteConfig.url + "/blog";
+const jestImage = siteConfig.url + siteConfig.headerIcon;
+
+/****************************************************************************/
+
+let readMetadata;
+let Metadata;
+
+function reloadMetadata() {
+ removeFromCache("./readMetadata.js");
+ readMetadata = require("./readMetadata.js");
+ readMetadata.generateDocsMetadata();
+ removeFromCache("../core/metadata.js");
+ Metadata = require("../core/metadata.js");
+}
+
+/****************************************************************************/
+
+// remove a module and child modules from require cache, so server does not have
+// to be restarted
+const removeFromCache = moduleName => {
+ let mod = require.resolve(moduleName);
+ if (mod && (mod = require.cache[mod])) {
+ (function traverse(mod) {
+ mod.children.forEach(child => {
+ traverse(child);
+ });
+ delete require.cache[mod.id];
+ })(mod);
+ }
+
+ Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
+ if (cacheKey.indexOf(moduleName) > 0) {
+ delete module.constructor._pathCache[cacheKey];
+ }
+ });
+};
+
+reloadMetadata();
+
+module.exports = function(type) {
+ console.log("feed.js triggered...");
+
+ type = type || "rss";
+
+ removeFromCache(CWD + "/siteConfig.js");
+ if (fs.existsSync(__dirname + "/../core/MetadataBlog.js")) {
+ removeFromCache("../core/MetadataBlog.js");
+ fs.removeSync(__dirname + "/../core/MetadataBlog.js");
+ }
+ readMetadata.generateBlogMetadata();
+ const MetadataBlog = require("../core/MetadataBlog.js");
+
+ const feed = new Feed({
+ title: siteConfig.title + " Blog",
+ description:
+ "The best place to stay up-to-date with the latest " +
+ siteConfig.title +
+ " news and events.",
+ id: blogRootURL,
+ link: blogRootURL,
+ image: jestImage,
+ copyright: siteConfig.copyright,
+ updated: new Date(MetadataBlog[0].date)
+ });
+
+ MetadataBlog.forEach(post => {
+ const url = blogRootURL + "/" + post.path;
+ let content = "";
+ let contentArr = post.content.split("");
+ if (contentArr.length > 0) {
+ content = contentArr[0];
+ }
+ content = content.trim().substring(0, 250);
+
+ feed.addItem({
+ title: post.title,
+ link: url,
+ author: [
+ {
+ name: post.author,
+ link: post.authorURL
+ }
+ ],
+ date: new Date(post.date),
+ description: content
+ });
+ });
+
+ return type === "rss" ? feed.rss2() : feed.atom1();
+};
diff --git a/lib/server/generate.js b/lib/server/generate.js
index 19cd2b8699..f9d54adf2b 100644
--- a/lib/server/generate.js
+++ b/lib/server/generate.js
@@ -23,6 +23,8 @@ function execute() {
const translate = require("./translate.js");
const versionFallback = require("./versionFallback.js");
+ const feed = require("./feed.js");
+
const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js");
const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json");
@@ -174,7 +176,7 @@ function execute() {
"](" + link
);
});
-
+
// replace any relative links to static assets to absolute links
rawContent = rawContent.replace(
/\]\(assets\//g,
@@ -225,11 +227,11 @@ function execute() {
.replace(/\./g, "-")
.replace(/\-md$/, ".html");
const result = readMetadata.extractMetadata(
- fs.readFileSync(file, { encoding: "utf8" })
+ fs.readFileSync(file, {encoding: "utf8"})
);
const rawContent = result.rawContent;
const metadata = Object.assign(
- { path: filePath, content: rawContent },
+ {path: filePath, content: rawContent},
result.metadata
);
metadata.id = metadata.title;
@@ -255,7 +257,7 @@ function execute() {
const perPage = 10;
for (let page = 0; page < Math.ceil(MetadataBlog.length / perPage); page++) {
let language = "en";
- const metadata = { page: page, perPage: perPage };
+ const metadata = {page: page, perPage: perPage};
const blogPageComp = (
0) {
+ let targetFile =
+ CWD + "/build/" + siteConfig.projectName + "/blog/" + "feed.xml";
+ writeFileAndCreateFolder(targetFile, feed());
+ targetFile =
+ CWD + "/build/" + siteConfig.projectName + "/blog/" + "atom.xml";
+ writeFileAndCreateFolder(targetFile, feed("atom"));
+ }
// copy blog assets if they exist
if (fs.existsSync(CWD + "/blog/assets")) {
@@ -375,7 +386,7 @@ function execute() {
// copy and compile a page for each enabled language from the English file
for (let i = 0; i < enabledLanguages.length; i++) {
let language = enabledLanguages[i];
- // skip conversion from english file if a file exists for this language
+ // skip conversion from english file if a file exists for this language
if (
language !== "en" &&
fs.existsSync(file.replace("/en/", "/" + language + "/"))
diff --git a/lib/server/readMetadata.js b/lib/server/readMetadata.js
index 8b83f203c2..8e0fa83a3e 100644
--- a/lib/server/readMetadata.js
+++ b/lib/server/readMetadata.js
@@ -92,7 +92,7 @@ function extractMetadata(content) {
const both = splitHeader(content);
// if no content returned, then that means there was no header, and both.header is the content
if (!both.content) {
- return { metadata, rawContent: both.header };
+ return {metadata, rawContent: both.header};
}
const lines = both.header.split("\n");
for (let i = 0; i < lines.length - 1; ++i) {
@@ -104,7 +104,7 @@ function extractMetadata(content) {
} catch (e) {}
metadata[key] = value;
}
- return { metadata, rawContent: both.content };
+ return {metadata, rawContent: both.content};
}
// process the metadata for a document found in the docs folder
@@ -173,7 +173,7 @@ function processMetadata(file) {
}
}
- return { metadata, rawContent: rawContent };
+ return {metadata, rawContent: rawContent};
}
// process metadata for all docs and save into core/metadata.js
@@ -295,13 +295,26 @@ function generateBlogMetadata() {
.replace("-", "/")
.replace(/\./g, "-")
.replace(/\-md$/, ".html");
- const result = extractMetadata(fs.readFileSync(file, { encoding: "utf8" }));
+ const result = extractMetadata(fs.readFileSync(file, {encoding: "utf8"}));
const rawContent = result.rawContent;
const metadata = Object.assign(
- { path: filePath, content: rawContent },
+ {path: filePath, content: rawContent},
result.metadata
);
+
metadata.id = metadata.title;
+
+ // Extract, YYYY, MM, DD from the file name
+ let filePathDateArr = path.basename(file).toString().split("-");
+ metadata.date = new Date(
+ filePathDateArr[0] +
+ "-" +
+ filePathDateArr[1] +
+ "-" +
+ filePathDateArr[2] +
+ "T06:00:00.000Z"
+ );
+
metadatas.push(metadata);
});
diff --git a/lib/server/server.js b/lib/server/server.js
index 5c0401b2ac..e8614a5161 100644
--- a/lib/server/server.js
+++ b/lib/server/server.js
@@ -23,6 +23,8 @@ function execute(port) {
const translate = require("./translate.js");
const versionFallback = require("./versionFallback");
+ const feed = require("./feed.js");
+
const CWD = process.cwd();
const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js");
const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json");
@@ -116,7 +118,7 @@ function execute(port) {
const metadata = Metadata[id];
links[metadata.permalink] = id;
});
-
+
// mdToHtml is a map from a markdown file name to its html link, used to
// change relative markdown links that work on GitHub into actual site links
const mdToHtml = {};
@@ -219,6 +221,16 @@ function execute(port) {
res.send(renderToStaticMarkup(docComp));
});
+ app.get(/blog\/.*xml$/, (req, res) => {
+ res.set("Content-Type", "application/rss+xml");
+ let parts = req.path.toString().split("blog/");
+ if (parts[1].toLowerCase() == "atom.xml") {
+ res.send(feed("atom"));
+ return;
+ }
+ res.send(feed("rss"));
+ });
+
// handle all requests for blog pages and posts
app.get(/blog\/.*html$/, (req, res) => {
removeFromCache(CWD + "/siteConfig.js");
@@ -242,7 +254,7 @@ function execute(port) {
page++
) {
let language = "en";
- const metadata = { page: page, perPage: perPage };
+ const metadata = {page: page, perPage: perPage};
const blogPageComp = (
+This line should never render in XML.
\ No newline at end of file
diff --git a/website/blog/2017-09-26-adding-rss.md b/website/blog/2017-09-26-adding-rss.md
new file mode 100644
index 0000000000..4d6d7ab164
--- /dev/null
+++ b/website/blog/2017-09-26-adding-rss.md
@@ -0,0 +1,12 @@
+---
+title: Adding RSS Support
+author: Eric Nakagawa
+authorURL: http://twitter.com/ericnakagawa
+authorFBID: ericnakagawa
+---
+
+This is a test post.
+
+
+
+A whole bunch of other information.
\ No newline at end of file
diff --git a/website/core/Footer.js b/website/core/Footer.js
index c5b18db88a..18717f8877 100644
--- a/website/core/Footer.js
+++ b/website/core/Footer.js
@@ -11,7 +11,6 @@ const React = require("react");
class Footer extends React.Component {
render() {
- const currentYear = new Date().getFullYear();
return (
);
diff --git a/website/package.json b/website/package.json
index 12ca66a5b0..20d6c14367 100644
--- a/website/package.json
+++ b/website/package.json
@@ -9,5 +9,8 @@
"rename-version": "../lib/rename-version.js",
"crowdin-upload": "crowdin-cli --config ../crowdin.yaml upload sources --auto-update -b master",
"crowdin-download": "crowdin-cli --config ../crowdin.yaml download -b master"
+ },
+ "dependencies": {
+ "docusaurus": "^1.0.0-alpha.35"
}
}
diff --git a/website/siteConfig.js b/website/siteConfig.js
index ddc92fb176..643308385b 100644
--- a/website/siteConfig.js
+++ b/website/siteConfig.js
@@ -40,10 +40,10 @@ const siteConfig = {
editUrl:
"https://github.com/facebookexperimental/docusaurus/edit/master/docs/",
headerLinks: [
- { doc: "installation", label: "Docs" },
- { page: "help", label: "Help" },
- { blog: true, label: "Blog" },
- { languages: false },
+ {doc: "installation", label: "Docs"},
+ {page: "help", label: "Help"},
+ {blog: true, label: "Blog"},
+ {languages: false},
{
href: "https://github.com/facebookexperimental/docusaurus",
label: "GitHub"
@@ -53,7 +53,6 @@ const siteConfig = {
footerIcon: "img/docusaurus_monochrome.svg",
favicon: "img/docusaurus.ico",
// See https://docusaurus.io/docs/search for more information about Aloglia
- // search
algolia: {
apiKey: "3eb9507824b8be89e7a199ecaa1a9d2c",
indexName: "docusaurus"
@@ -62,7 +61,8 @@ const siteConfig = {
primaryColor: "#2E8555",
secondaryColor: "#205C3B",
prismColor: "rgba(46, 133, 85, 0.03)"
- }
+ },
+ copyright: "Copyright © " + new Date().getFullYear() + " Facebook Inc."
};
module.exports = siteConfig;