It's coming together, but we just have a whole bunch of errors to work through.
parent
d5160904ad
commit
8a863d7b0d
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{
|
||||
"author_name": "Starbeamrainbowlabs",
|
||||
"github_username": "sbrl",
|
||||
"feed_uri": "https://starbeamrainbowlabs.com/blog/feed.php"
|
||||
},
|
||||
{
|
||||
"author_name": "Edward Charles",
|
||||
"github_username": "closebracket",
|
||||
"feed_uri": "https://love.edwardcharl.es/rss/"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,13 @@
|
|||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@11ty/eleventy": "^0.12.1",
|
||||
"feedme": "^2.0.2"
|
||||
"dateformat": "^4.5.1",
|
||||
"feedme": "^2.0.2",
|
||||
"file-type": "^16.5.3",
|
||||
"html-entities": "^2.3.2",
|
||||
"p-reflect": "^2.1.0",
|
||||
"phin": "^3.6.0",
|
||||
"sha3": "^2.1.4",
|
||||
"striptags": "^3.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,53 @@ const os = require("os");
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const striptags = require("striptags");
|
||||
const htmlentities = require("html-entities");
|
||||
const { SHA3 } = require("sha3");
|
||||
const filetype = require("file-type");
|
||||
|
||||
const fetch = require("./lib/fetch.js");
|
||||
|
||||
function hash(str) {
|
||||
const hash = new SHA3(128);
|
||||
hash.update(str);
|
||||
return hash.digest("base64")
|
||||
.replaceAll("/", "-")
|
||||
.replaceAll("+", "_");
|
||||
}
|
||||
|
||||
async function filter_asset(src) {
|
||||
let target_dir = `./_site/img`;
|
||||
if(!fs.existsSync(target_dir))
|
||||
await fs.promises.mkdir(target_dir, { recursive: true });
|
||||
let filename = path.basename(src);
|
||||
|
||||
if(src.search(/https?/)) {
|
||||
let content = await fetch(src, "none");
|
||||
let type = await filetype.fromBuffer(content);
|
||||
// It's a URL - download it
|
||||
filename = `${hash(src)}.${type.ext}`;
|
||||
await fs.promises.writeFile(
|
||||
path.join(target_dir, filename),
|
||||
content
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Generally speaking we optimise PNGs *very* well with oxipng/Zopfli,
|
||||
// and the Image plugin doesn't respect this
|
||||
await fs.promises.copyFile(src, path.join(target_dir, filename));
|
||||
}
|
||||
|
||||
return `/img/${filename}`;
|
||||
}
|
||||
|
||||
module.exports = function(eleventyConfig) {
|
||||
eleventyConfig.addFilter("striphtml", (value) => striptags(value));
|
||||
eleventyConfig.addFilter("htmlentities", (value) => htmlentities.encode(value));
|
||||
|
||||
eleventyConfig.addFilter("asset", filter_asset);
|
||||
eleventyConfig.addAsyncShortcode("asset", filter_asset);
|
||||
eleventyConfig.addNunjucksAsyncShortcode("asset", filter_asset);
|
||||
|
||||
// eleventyConfig.addAsyncShortcode("fetch", fetch);
|
||||
//
|
||||
|
@ -15,4 +61,8 @@ module.exports = function(eleventyConfig) {
|
|||
// eleventyConfig.addAsyncShortcode("image_urlpass", shortcode_image_urlpass);
|
||||
// eleventyConfig.addNunjucksAsyncShortcode("image_urlpass", shortcode_image_urlpass);
|
||||
// eleventyConfig.addPairedShortcode("gallerybox", shortcode_gallerybox);
|
||||
|
||||
return {
|
||||
htmlTemplateEngine: "njk"
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
css/
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
site_name: Hull Blogs
|
||||
root_url: https://hullblogs.com
|
||||
description: "Description of hullblogs.com website here"
|
||||
---
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<title>{{ title }} • {{ site_name }}</title>
|
||||
|
||||
<link rel="stylesheet" href="/theme.css" />
|
||||
|
||||
<link rel="icon" href="{% asset './favicon-64.png' %}" type="image/png" sizes="64x64" />
|
||||
<link rel="icon" href="{% asset './favicon.png' %}" type="image/png" sizes="540x540" />
|
||||
|
||||
<meta name="theme-color" content="#61b4f4" />
|
||||
|
||||
<!-- OpenGraph -->
|
||||
<meta property="og:title" content="{{ site_name }}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="{{ root_url }}/" />
|
||||
<meta property="og:image" content="{{ root_url }}{% asset 'images/banner-main.jpeg' %}" />
|
||||
<meta property="og:description" content="{{ description }}" />
|
||||
|
||||
<!-- Twitter Cards -->
|
||||
<meta property="twitter:card" content="summary" />
|
||||
<meta property="twitter:site" content="@SBRLabs" />
|
||||
<meta property="twitter:title" content="{{ site_name }}" />
|
||||
<meta property="twitter:description" content="{{ description }}" />
|
||||
<meta property="twitter:image" content="{{ root_url }}/{% asset '../favicon.png' %}" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="shadow-bottom">
|
||||
<h1><a href="/" class="invisilink">
|
||||
{{ site_name }}
|
||||
</a></h1>
|
||||
<ul>
|
||||
{% for navitem in collections.navigable %}
|
||||
<li {% if page.url == navitem.url %}aria-current="page"{% endif %}>
|
||||
<a href="{{ navitem.url }}" class="nav">{{ navitem.data.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li><a href="https://github.com/sbrl/Minetest-WorldEditAdditions/" class="nav image"><img src="{% asset 'images/github.svg' %}" alt="GitHub" title="GitHub" /></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
<footer class="shadow-top">
|
||||
<p>hullblogs.com built with ❤️ by <a href="https://starbeamrainbowlabs.com/"><img src="{% asset 'https://starbeamrainbowlabs.com/images/sbrl/SBRL-Small-200.png' %}" alt="Starbeamrainbowlabs' logo" aria-hidden="true" />Starbeamrainbowlabs</p>
|
||||
|
||||
<p>Tech: <a href="https://www.11ty.dev/">Eleventy</a> (this website), <a href="https://www.heropatterns.com/">Hero Patterns</a> (background patterns), <a href="https://github.com/shssoichiro/oxipng">Oxipng</a> (PNG image compression), <a href="https://www.npmjs.com/package/feedme"><code>feedme</code></a> (for prsing feeds)</p>
|
||||
<p>Licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache Licence 2.0</a> (<a href="https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)">tldr</a>)</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,64 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const pReflect = require("p-reflect");
|
||||
const dateformat = require("dateformat");
|
||||
const striptags = require("striptags");
|
||||
|
||||
const fetch_feed = require("./lib/fetch_feed.js");
|
||||
|
||||
// The length of auto-generated descriptions if one isn't provided.
|
||||
const DESCRIPTION_LENGTH = 200;
|
||||
|
||||
module.exports = async function() {
|
||||
const feeds = JSON.parse(await fs.promises.readFile("../feeds.json", "utf-8"));
|
||||
|
||||
const feed_data = await Promise.all(feeds.map(async (feed) => { return {
|
||||
author_name: feed.author_name,
|
||||
author_image: `https://avatars.githubusercontent.com/${encodeURIComponent(feed.github_username)}`,
|
||||
data: await pReflect(fetch_feed(feed.feed_uri))
|
||||
} }));
|
||||
const feed_data_ok = feed_data.filter(el => {
|
||||
return el.data.isFulfilled
|
||||
})
|
||||
.map((feed) => {
|
||||
feed.data = feed.data.value;
|
||||
return feed;
|
||||
});
|
||||
const feed_authors_error = feed_data.filter(el => el.data.isRejected)
|
||||
.map(el => el.author_name);
|
||||
|
||||
const feed_items = [].concat(...feed_data_ok.map(feed => feed.data.items.map(item => {
|
||||
// console.log(`FEED ITEM`, item);
|
||||
item.author_name = feed.author_name;
|
||||
item.parent = feed.data;
|
||||
|
||||
if(!item.content) item.content = item["content:encoded"] || "";
|
||||
if(!item.description) item.description = striptags(item.content)
|
||||
.substr(0, DESCRIPTION_LENGTH);
|
||||
|
||||
if(!item.pubdate) item.pubdate = item.published
|
||||
|| item.updated
|
||||
|| new Date("1970-01-01");
|
||||
|
||||
item.pubdate_iso = new Date(item.pubdate).toISOString();
|
||||
item.pubdate_display = dateformat(
|
||||
new Date(item.pubdate),
|
||||
"ddd dS mmmm yyyy h:MM:ss TT Z"
|
||||
);
|
||||
return item;
|
||||
})));
|
||||
|
||||
return {
|
||||
layout: "main.njk",
|
||||
title: "Posts",
|
||||
tags: "navigable",
|
||||
date: "2000-01-01", // For sorting in the navigation bar
|
||||
feed_items: feed_items,
|
||||
feeds_errored: feed_authors_error,
|
||||
pagination: {
|
||||
data: "feed_items",
|
||||
size: 15
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
<section class="posts">
|
||||
|
||||
{% for post in pagination.items %}
|
||||
|
||||
<article class="post">
|
||||
<h2><a href="{{ post.link }}">{{ post.title | striphtml | htmlentities }}</a></h2>
|
||||
<div class="post-extract">
|
||||
{{ post.description | striphtml | htmlentities }}
|
||||
</div>
|
||||
<div>
|
||||
<span><a href="{{ post.parent.data.link | htmlentities }}"><img src="{{ post.parent.author_image }}" alt="{{ post.parent.author_name | htmlentities }} avatar" aria-hidden="true" /> {{ post.parent.author_name | htmlentities }}</a></span>
|
||||
<span><time datetime="{{ post.pubdate_iso }}">{{ post.pubdate_display | htmlentities }}</time></span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</section>
|
||||
|
||||
<nav>
|
||||
<span>{% if page.url != pagination.href.first %}<a href="{{ pagination.href.first }}">First</a>{% else %}First{% endif %}</span>
|
||||
|
||||
<span>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</span>
|
||||
|
||||
{% for pageKey in pagination.pages %}
|
||||
<a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if pagination.hrefs[ loop.index0 ] == page.url %} aria-current="page"{% endif %}>{{ loop.index }}</a>
|
||||
{% endfor %}
|
||||
|
||||
<span>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</span>
|
||||
|
||||
<span>{% if page.url != pagination.href.last %}<a href="{{ pagination.href.last }}">Last</a>{% else %}Last{% endif %}</span>
|
||||
</nav>
|
|
@ -0,0 +1,23 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
const phin = require("phin");
|
||||
|
||||
async function fetch(url, format = "string") {
|
||||
let package = JSON.parse(await fs.promises.readFile(
|
||||
path.join(path.dirname(path.dirname(__dirname)), "package.json"), "utf8"
|
||||
));
|
||||
|
||||
return (await phin({
|
||||
url,
|
||||
headers: {
|
||||
"user-agent": `HullBlogsStaticBuilder/${package.version} (Node.js/${process.version}; ${os.platform()} ${os.arch()}) eleventy/${package.dependencies["@11ty/eleventy"].replace(/\^/, "")}`
|
||||
},
|
||||
followRedirects: true,
|
||||
parse: format
|
||||
})).body;
|
||||
}
|
||||
|
||||
|
||||
module.exports = fetch;
|
|
@ -0,0 +1,27 @@
|
|||
const fetch_stream = require("./fetch_stream.js");
|
||||
const FeedMe = require("feedme");
|
||||
const events = require("events");
|
||||
|
||||
function do_parse(stream) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const parser = new FeedMe(true);
|
||||
parser.once("error", reject);
|
||||
stream.pipe(parser);
|
||||
events.once(parser, "end").then(() => {
|
||||
parser.off("error", reject);
|
||||
resolve(parser.done());
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async function fetch_feed(url) {
|
||||
let start = new Date();
|
||||
let result = await do_parse(
|
||||
await fetch_stream(url)
|
||||
);
|
||||
console.log(`FETCH ${new Date() - start}ms ${url}`);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = fetch_feed;
|
|
@ -0,0 +1,23 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
const phin = require("phin");
|
||||
|
||||
async function fetch_stream(url) {
|
||||
let package = JSON.parse(await fs.promises.readFile(
|
||||
path.join(path.dirname(path.dirname(__dirname)), "package.json"), "utf8"
|
||||
));
|
||||
|
||||
return (await phin({
|
||||
url,
|
||||
headers: {
|
||||
"user-agent": `HullBlogsStaticBuilder/${package.version} (Node.js/${process.version}; ${os.platform()} ${os.arch()}) eleventy/${package.dependencies["@11ty/eleventy"].replace(/\^/, "")}`
|
||||
},
|
||||
followRedirects: true,
|
||||
stream: true
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
module.exports = fetch_stream;
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
permalink: theme.css
|
||||
---
|
||||
|
||||
{% include "css/theme.css" %}
|
||||
{% include "css/smallscreens.css" %}
|
||||
|
||||
|
||||
{# {% fetch "https://unpkg.com/prismjs/themes/prism-okaidia.css" %} #}
|
||||
{# {% fetch "https://raw.githubusercontent.com/PrismJS/prism-themes/master/themes/prism-shades-of-purple.css" %} #}
|
||||
{# {% fetch "https://raw.githubusercontent.com/PrismJS/prism-themes/master/themes/prism-material-light.css" %} #}
|
Loading…
Reference in New Issue