Merge pull request #45 from EbookFoundation/feature/about-pages

Feature/about pages
pull/47/head
Theodore Kluge 2019-03-13 12:56:20 -04:00 committed by GitHub
commit 962aa0acb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 550 additions and 113 deletions

View File

@ -1,34 +1,18 @@
# roe-base
# River of Ebooks
https://github.com/EbookFoundation/RoE-pipe
a [Sails v1](https://sailsjs.com) application
### Links
+ [Get started](https://sailsjs.com/get-started)
+ [Sails framework documentation](https://sailsjs.com/documentation)
+ [Version notes / upgrading](https://sailsjs.com/documentation/upgrading)
+ [Deployment tips](https://sailsjs.com/documentation/concepts/deployment)
+ [Community support options](https://sailsjs.com/support)
+ [Professional / enterprise options](https://sailsjs.com/enterprise)
## About
The River of Ebooks serves as an easy-to-use ebook aggregator. Publishers can send metadata from new and updated ebooks through the River where it will be available for any downstream consumers to read, allowing for a more widely available ebook collection. This way, ebooks can be made available on all end user sites, instead of only the site they were published with.
-----
### Version info
This app was originally generated on Tue Oct 16 2018 01:21:31 GMT+0000 (UTC) using Sails v1.0.2.
<!-- Internally, Sails used [`sails-generate@1.15.28`](https://github.com/balderdashy/sails-generate/tree/v1.15.28/lib/core-generators/new). -->
<!--
Note: Generators are usually run using the globally-installed `sails` CLI (command-line interface). This CLI version is _environment-specific_ rather than app-specific, thus over time, as a project's dependencies are upgraded or the project is worked on by different developers on different computers using different versions of Node.js, the Sails dependency in its package.json file may differ from the globally-installed Sails CLI release it was originally generated with. (Be sure to always check out the relevant [upgrading guides](https://sailsjs.com/upgrading) before upgrading the version of Sails used by your app. If you're stuck, [get help here](https://sailsjs.com/support).)
-->
[![Build Status](https://travis-ci.org/miacona96/RoE-pipe.svg?branch=master)](https://travis-ci.org/miacona96/RoE-pipe)
### Setup
a [Sails v1](https://sailsjs.com) application
[![Build Status](https://travis-ci.org/miacona96/RoE-pipe.svg?branch=master)](https://travis-ci.org/miacona96/RoE-pipe)
#### Standalone

View File

@ -0,0 +1,21 @@
module.exports = {
show: async function (req, res) {
const docsHelper = await sails.helpers.docs()
const content = await docsHelper.read('README', '../../')
res.view('pages/index', {
content
})
},
docs: async function (req, res) {
const docsHelper = await sails.helpers.docs()
const page = req.param('page')
if (!page || !(['api', 'integrations', 'webhooks'].includes(page))) {
return res.notFound()
}
const content = await docsHelper.read(page)
res.view('pages/index', {
active: page,
content
})
}
}

35
api/helpers/docs.js Normal file
View File

@ -0,0 +1,35 @@
const showdown = require('showdown')
const fs = require('fs')
const path = require('path')
showdown.setFlavor('github')
const converter = new showdown.Converter()
module.exports = {
friendlyName: 'Load DocsHelper',
description: 'Load a DocsHelper instance',
inputs: {},
exits: {
success: {
outputFriendlyName: 'Docs helper',
outputDescription: 'A DocsHelper instance'
}
},
fn: async function (inputs, exits) {
return exits.success(new DocsHelper())
}
}
class DocsHelper {
read (file, relPath = '../../docs') {
return new Promise((resolve, reject) => {
fs.readFile(path.join(__dirname, relPath, `${file}.md`), { encoding: 'utf8' }, (err, data) => {
if (err) reject(err)
resolve(converter.makeHtml(data))
})
})
}
convert (md) {
return converter.makeHtml(md)
}
}

View File

@ -80,3 +80,106 @@
}
}
}
.home {
header {
height: 50px;
line-height: 50px;
.logo {
color: $black-1;
text-decoration: none;
font-size: 1.2em;
padding: 0 20px;
}
nav {
a {
text-decoration: none;
display: inline-block;
line-height: 50px;
padding: 0 20px;
color: $accent-2;
&:hover {
text-decoration: underline;
}
&:last-of-type {
line-height: 40px;
height: 40px;
margin: 5px 20px 5px 0;
background: $accent-1;
color: $text-light-1;
border-radius: 3px;
}
}
}
}
footer {
height: 40px;
line-height: 40px;
background: $accent-1;
color: white;
padding: 0 20px;
box-shadow: $shadow-3;
a {
color: $accent-3;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
main {
background: white;
width: 85%;
max-width: 900px;
box-shadow: $shadow-1;
padding: 100px 60px 140px 60px;
margin: 60px auto 100px auto;
h2,
h3,
h4 {
margin: 40px 0 10px 0;
font-weight: normal;
color: $black-1;
}
hr {
border: none;
border-top: 1px solid $black-3;
margin: 40px 80px;
}
a {
color: $accent-2;
}
pre {
background: $black-5;
padding: 10px;
border-radius: 3px;
&:before {
display: block;
content: '';
background: $accent-3;
height: 100%;
width: 2px;
top: 0;
left: 0;
}
code {
background: transparent;
padding: 0;
}
}
code {
background: $black-5;
padding: 2px 5px;
border-radius: 3px;
}
p {
line-height: 1.4em;
}
}
}

View File

@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
<!DOCTYPE html>
<html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>River of Ebooks | admin</title>
@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<link<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %> /><%
} %>
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1" />
</head>
<body>
<div id="root"></div>

View File

@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
<!DOCTYPE html>
<html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>River of Ebooks</title>
@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<link<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %> /><%
} %>
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1" />
</head>
<body>
<div id="root"></div>

View File

@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
<!DOCTYPE html>
<html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>River of Ebooks - Login</title>
@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<link<% for (key in item) { %> <%= key %>="<%= item[key] %>"<% } %> /><%
} %>
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1" />
</head>
<body>
<div id="root"></div>

View File

@ -22,9 +22,9 @@ module.exports.routes = {
* *
***************************************************************************/
'GET /': {
view: 'pages/index'
},
'GET /': 'HomeController.show',
'GET /docs/:page': 'HomeController.docs',
'GET /login': {
view: 'pages/login'
},

View File

@ -23,7 +23,7 @@ and body:
Each tuple of `(title, author, version, isbn)` must be unique.
The `opds` parameter is an opds2 file sent along with the post body.
The `opds` parameter is an opds2 file containing an opds Publication sent along with the post body.
The server will respond with either:

13
docs/integrations.md Normal file
View File

@ -0,0 +1,13 @@
# River of Ebooks Integrations
## Information on existing RoE integrations with other websites and services
### - readthedocs.org
[view on github](https://github.com/ghowardsit/readthedocs.org)
New ebooks published using ReadTheDocs will automatically be sent to the River of Ebooks.
## Information on building your own integration
To publish ebook metadata through the River of Ebooks, you will first need to register an account and then create a publisher.
Verifying your ownership of the publisher's domain will increase the chance that your publisher is whitelisted. Once whitelisted, you will be able to use your publisher's appid (key) and secret to POST metadata through the River. You can view the [API documentation here](docs/api). Publishing books is easy - and once published, each new ebook will be available for downstream consumers to find.

View File

@ -1,4 +1,9 @@
# River of Ebooks signed requests
# River of Ebooks webhooks and signed requests
## Information on how to receive new publications from RoE
To have RoE send your service any newly published or updated ebooks, you will first need to register an account and then create a Push URI. RoE will send a POST request containing the OPDS2 metadata from any published or updated book to each valid URL. The POST body structure can be viewed in the [API documentation](docs/api).
## Information on how to verify that requests are sent by RoE
1. Grab your Signing Secret from the bottom of the 'My account' page. In this example, the Signing Secret is `919ac0b6c07b50`. Additionally, extract the raw request body from the request.

View File

@ -52,6 +52,7 @@
"sails-hook-orm": "^2.1.1",
"sails-hook-sockets": "^1.4.0",
"sails-postgresql": "^1.0.2",
"showdown": "^1.9.0",
"ta-json-x": "^2.5.0",
"xmldom": "^0.1.27"
},

View File

@ -3,6 +3,7 @@ dependencies:
r2-utils-js: 1.0.6
request: 2.88.0
sails-postgresql: 1.0.2
showdown: 1.9.0
ta-json-x: 2.5.0
xmldom: 0.1.27
devDependencies:
@ -35,6 +36,12 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
/ansi-regex/3.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
/ansi-styles/2.2.1:
dev: false
engines:
@ -176,6 +183,12 @@ packages:
node: '>=0.2.0'
resolution:
integrity: sha1-skV5w77U1tOWru5tmorn9Ugqt7s=
/camelcase/4.1.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
/caseless/0.12.0:
dev: false
resolution:
@ -198,6 +211,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
/cliui/4.1.0:
dependencies:
string-width: 2.1.1
strip-ansi: 4.0.0
wrap-ansi: 2.1.0
dev: false
resolution:
integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
/code-point-at/1.1.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
/combined-stream/1.0.7:
dependencies:
delayed-stream: 1.0.0
@ -222,6 +249,14 @@ packages:
dev: false
resolution:
integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
/cross-spawn/5.1.0:
dependencies:
lru-cache: 4.1.5
shebang-command: 1.2.0
which: 1.3.1
dev: false
resolution:
integrity: sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
/dashdash/1.14.1:
dependencies:
assert-plus: 1.0.0
@ -248,6 +283,12 @@ packages:
dev: false
resolution:
integrity: sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
/decamelize/1.2.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
/delayed-stream/1.0.0:
dev: false
engines:
@ -285,6 +326,20 @@ packages:
node: '>=0.8.0'
resolution:
integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
/execa/0.7.0:
dependencies:
cross-spawn: 5.1.0
get-stream: 3.0.0
is-stream: 1.1.0
npm-run-path: 2.0.2
p-finally: 1.0.0
signal-exit: 3.0.2
strip-eof: 1.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
/expand-brackets/0.1.5:
dependencies:
is-posix-bracket: 0.1.1
@ -392,6 +447,14 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
/find-up/2.1.0:
dependencies:
locate-path: 2.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
/findup-sync/0.4.3:
dependencies:
detect-file: 0.1.0
@ -486,6 +549,16 @@ packages:
node: '>= 0.8.0'
resolution:
integrity: sha1-OMYYhRPhQDCUjsblz2VSPZd5KZs=
/get-caller-file/1.0.3:
dev: false
resolution:
integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
/get-stream/3.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
/getpass/0.1.7:
dependencies:
assert-plus: 1.0.0
@ -630,6 +703,12 @@ packages:
dev: true
resolution:
integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
/invert-kv/1.0.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
/is-buffer/1.1.6:
dev: false
resolution:
@ -660,6 +739,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
/is-fullwidth-code-point/1.0.0:
dependencies:
number-is-nan: 1.0.1
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
/is-fullwidth-code-point/2.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
/is-glob/2.0.1:
dependencies:
is-extglob: 1.0.0
@ -694,6 +787,12 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
/is-stream/1.1.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
/is-typedarray/1.0.0:
dev: false
resolution:
@ -814,6 +913,14 @@ packages:
hasBin: true
resolution:
integrity: sha1-V5P1efB6KTi/mHRpPXS7pVxbqhw=
/lcid/1.0.0:
dependencies:
invert-kv: 1.0.0
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
/liftoff/2.2.5:
dependencies:
extend: 3.0.2
@ -830,6 +937,15 @@ packages:
dev: false
resolution:
integrity: sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=
/locate-path/2.0.0:
dependencies:
p-locate: 2.0.0
path-exists: 3.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
/lodash/4.17.11:
dev: false
resolution:
@ -841,6 +957,13 @@ packages:
hasBin: true
resolution:
integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
/lru-cache/4.1.5:
dependencies:
pseudomap: 1.0.2
yallist: 2.1.2
dev: false
resolution:
integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
/machine/15.2.2:
dependencies:
'@sailshq/lodash': 3.10.3
@ -867,6 +990,14 @@ packages:
dev: false
resolution:
integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
/mem/1.1.0:
dependencies:
mimic-fn: 1.2.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
/micromatch/2.3.11:
dependencies:
arr-diff: 2.0.0
@ -901,6 +1032,12 @@ packages:
node: '>= 0.6'
resolution:
integrity: sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
/mimic-fn/1.2.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
/minimatch/3.0.4:
dependencies:
brace-expansion: 1.1.11
@ -952,6 +1089,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
/npm-run-path/2.0.2:
dependencies:
path-key: 2.0.1
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
/number-is-nan/1.0.1:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
/oauth-sign/0.9.0:
dev: false
resolution:
@ -989,6 +1140,44 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
/os-locale/2.1.0:
dependencies:
execa: 0.7.0
lcid: 1.0.0
mem: 1.1.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
/p-finally/1.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
/p-limit/1.3.0:
dependencies:
p-try: 1.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
/p-locate/2.0.0:
dependencies:
p-limit: 1.3.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
/p-try/1.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
/packet-reader/0.2.0:
dev: false
resolution:
@ -1018,12 +1207,24 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
/path-exists/3.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
/path-is-absolute/1.0.1:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
/path-key/2.0.1:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
/path-parse/1.0.6:
dev: false
resolution:
@ -1142,6 +1343,10 @@ packages:
dev: false
resolution:
integrity: sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=
/pseudomap/1.0.2:
dev: false
resolution:
integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
/psl/1.1.31:
dev: false
resolution:
@ -1394,6 +1599,16 @@ packages:
node: '>= 4'
resolution:
integrity: sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
/require-directory/2.1.1:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
/require-main-filename/1.0.1:
dev: false
resolution:
integrity: sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
/resolve-dir/0.1.1:
dependencies:
expand-tilde: 1.2.2
@ -1457,10 +1672,39 @@ packages:
hasBin: true
resolution:
integrity: sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
/set-blocking/2.0.0:
dev: false
resolution:
integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
/setimmediate/1.0.5:
dev: false
resolution:
integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
/shebang-command/1.2.0:
dependencies:
shebang-regex: 1.0.0
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
/shebang-regex/1.0.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
/showdown/1.9.0:
dependencies:
yargs: 10.1.2
dev: false
hasBin: true
resolution:
integrity: sha512-x7xDCRIaOlicbC57nMhGfKamu+ghwsdVkHMttyn+DelwzuHOx4OHCVL/UW/2QOLH7BxfCcCCVVUix3boKXJKXQ==
/signal-exit/3.0.2:
dev: false
resolution:
integrity: sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
/slugify/1.3.4:
dev: false
engines:
@ -1496,6 +1740,25 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
/string-width/1.0.2:
dependencies:
code-point-at: 1.1.0
is-fullwidth-code-point: 1.0.0
strip-ansi: 3.0.1
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
/string-width/2.1.1:
dependencies:
is-fullwidth-code-point: 2.0.0
strip-ansi: 4.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
/string_decoder/0.10.31:
dev: false
resolution:
@ -1514,6 +1777,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
/strip-ansi/4.0.0:
dependencies:
ansi-regex: 3.0.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=
/strip-eof/1.0.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
/supports-color/2.0.0:
dev: false
engines:
@ -1678,6 +1955,10 @@ packages:
dev: false
resolution:
integrity: sha512-WsS1yRw8xT6O7iIK8oAcYr3/vhMYiTHdA/vQnU/JsGbcad2Xi4p8bie8/F+BoEyN7SEpBZ8nFT9OdszDAt7Ugg==
/which-module/2.0.0:
dev: false
resolution:
integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
/which/1.3.1:
dependencies:
isexe: 2.0.0
@ -1685,6 +1966,15 @@ packages:
hasBin: true
resolution:
integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
/wrap-ansi/2.1.0:
dependencies:
string-width: 1.0.2
strip-ansi: 3.0.1
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
/wrappy/1.0.2:
dev: false
resolution:
@ -1707,6 +1997,37 @@ packages:
node: '>=0.4'
resolution:
integrity: sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
/y18n/3.2.1:
dev: false
resolution:
integrity: sha1-bRX7qITAhnnA136I53WegR4H+kE=
/yallist/2.1.2:
dev: false
resolution:
integrity: sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
/yargs-parser/8.1.0:
dependencies:
camelcase: 4.1.0
dev: false
resolution:
integrity: sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
/yargs/10.1.2:
dependencies:
cliui: 4.1.0
decamelize: 1.2.0
find-up: 2.1.0
get-caller-file: 1.0.3
os-locale: 2.1.0
require-directory: 2.1.1
require-main-filename: 1.0.1
set-blocking: 2.0.0
string-width: 2.1.1
which-module: 2.0.0
y18n: 3.2.1
yargs-parser: 8.1.0
dev: false
resolution:
integrity: sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
/yauzl/2.10.0:
dependencies:
buffer-crc32: 0.2.13
@ -1730,5 +2051,6 @@ specifiers:
react-router-dom: ^4.3.1
request: ^2.88.0
sails-postgresql: ^1.0.2
showdown: ^1.9.0
ta-json-x: ^2.5.0
xmldom: ^0.1.27

File diff suppressed because one or more lines are too long

3
views/shared/footer.html Normal file
View File

@ -0,0 +1,3 @@
<footer>
<span>River of Ebooks is a project of the <a href="https://ebookfoundation.org">Free Ebook Foundation</a>.</span>
</footer>

10
views/shared/header.html Normal file
View File

@ -0,0 +1,10 @@
<header class="flex-container header">
<a href="/" class="logo">River of Ebooks</a>
<div class="flex"></div>
<nav>
<a href="/docs/integrations">Integrations</a>
<a href="/docs/webhooks">Webhooks</a>
<a href="/docs/api">API</a>
<a href="/login">Sign in</a>
</nav>
</header>