diff --git a/marko/page/story/components/page/index.marko b/marko/page/story/components/page/index.marko
index 5764a29..acf15bb 100644
--- a/marko/page/story/components/page/index.marko
+++ b/marko/page/story/components/page/index.marko
@@ -1,4 +1,4 @@
-
+
diff --git a/marko/page/story/components/story-menu/index.marko b/marko/page/story/components/story-menu/index.marko
index cab21c3..b2d78f4 100644
--- a/marko/page/story/components/story-menu/index.marko
+++ b/marko/page/story/components/story-menu/index.marko
@@ -6,6 +6,16 @@
Categories
${category.name}
+
+ Month
+ ${input.menuMonth}
+
+
+
+ Author
+ ${input.menuAuthor}
+
+
Tags
${tag.name}
Tags
diff --git a/routes/story/by-author.js b/routes/story/by-author.js
new file mode 100644
index 0000000..9256006
--- /dev/null
+++ b/routes/story/by-author.js
@@ -0,0 +1,23 @@
+const express = require("express")
+const router = express.Router()
+
+const common = require("./common")
+const {storyApi} = require("../../rpdata/api/Story")
+
+const listTemplate = require("../../marko/page/story/list.marko")
+
+router.get("/:author", common, async(req, res) => {
+ res.locals.menuAuthor = req.params.author
+
+ try {
+ res.markoAsync(listTemplate, {
+ stories: storyApi.list({author: req.params.author}),
+ menuAuthor: req.params.author,
+ selected: {special: "author"},
+ })
+ } catch(err) {
+ console.error(err)
+ }
+})
+
+module.exports = router
diff --git a/routes/story/by-month.js b/routes/story/by-month.js
new file mode 100644
index 0000000..0f68500
--- /dev/null
+++ b/routes/story/by-month.js
@@ -0,0 +1,31 @@
+const express = require("express")
+const router = express.Router()
+
+const common = require("./common")
+const {storyApi} = require("../../rpdata/api/Story")
+
+const listTemplate = require("../../marko/page/story/list.marko")
+
+router.get("/:yearmonth(\-{0,1}[0-9]{4}\-[0-9]{1,2})", common, async(req, res) => {
+ try {
+ const [year, month] = req.params.yearmonth.split("-").map(t => parseInt(t, 10))
+ if (month > 12) {
+ return res.status(400).end(`${month} is not a valid month number`)
+ }
+
+ // Month is zero-based, while input is one-based.
+ const fromDate = new Date(Date.UTC(year, month - 1, 1))
+ const toDate = new Date(Date.UTC(year, month, 1))
+ const monthStr = `${fromDate}-${month > 9 ? month : '0' + month}`
+
+ res.markoAsync(listTemplate, {
+ stories: storyApi.list({earliestFictionalDate: fromDate, latestFictionalDate: toDate}),
+ menuMonth: monthStr,
+ selected: {special: "month"},
+ })
+ } catch(err) {
+ console.error(err)
+ }
+})
+
+module.exports = router
diff --git a/server.js b/server.js
index f574aea..1f10bc2 100644
--- a/server.js
+++ b/server.js
@@ -73,6 +73,8 @@ app.use("/graphql", require("./routes/graphql"))
app.use("/story/", require("./routes/story"))
app.use("/story/by-category/", require("./routes/story/by-category"))
app.use("/story/by-tag/", require("./routes/story/by-tag"))
+app.use("/story/by-month/", require("./routes/story/by-month"))
+app.use("/story/by-author/", require("./routes/story/by-author"))
app.use("/story/tag-list/", require("./routes/story/tag-list"))
app.use("/story/:id(S[0-9a-z]{15})/", require("./routes/story-content"))
app.use("/logs/", require("./routes/logs"))