Almost done - add replies, webmentions, finish rendering posts from wordpress

This commit is contained in:
Lewis Dale committed 2023-02-16 14:10:05 +00:00
1 parent 5b68b1278c
commit b5d04b7360
9 files changed
+208 -60

No files matched your search

+101 -38
View File
@@ -1,6 +1,88 @@
const EleventyFetch = require('@11ty/eleventy-fetch');
const fs = require('fs');
const merge = require('lodash/merge')
const wordpressPassword = process.env.WORDPRESS_PASSWORD;
const auth = Buffer.from(`lewis:${wordpressPassword}`).toString('base64');
const dateSort = (a, b) => new Date(b.date) - new Date(a.date);
class PostCache {
constructor() {
this.readCache();
}
readCache() {
if (!fs.existsSync(".cache/wordpress_post_fetch.json")) {
this.last_read_date = null;
this.posts = {};
} else {
const data = JSON.parse(fs.readFileSync(".cache/wordpress_post_fetch.json"));
this.last_read_date = new Date(data.last_read_date);
this.posts = data.posts;
}
}
writeCache() {
fs.writeFileSync(".cache/wordpress_post_fetch.json", JSON.stringify(this, null, 2));
}
async fetchCommentsByType(type = "comment") {
const params = new URLSearchParams();
params.set("per_page", 100);
params.set("type", type);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://lewisdale.dev/wp-json/wp/v2/comments?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
return await response.json()
}
async fetchComments() {
const comments = [...await this.fetchCommentsByType(), ...await this.fetchCommentsByType("webmention")];
comments.forEach(comment => {
if (this.posts[comment.post]) {
this.posts[comment.post].comments[comment.id] = comment;
}
});
}
async fetchPosts() {
const params = new URLSearchParams();
params.set("per_page", 100);
if (this.last_read_date) {
params.set("modified_after", this.last_read_date.toISOString());
}
const response = await fetch(`https://lewisdale.dev/wp-json/wp/v2/posts?${params.toString()}`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
const posts = await response.json();
posts.forEach(post => {
this.posts[post.id] = merge({ comments: {} }, this.posts[post.id], post);
});
}
async fetchLatest() {
await this.fetchPosts();
await this.fetchComments();
this.last_read_date = new Date();
this.writeCache();
}
}
const mapComment = comment => ({
author: {
name: comment.author_name,
@@ -9,46 +91,27 @@ const mapComment = comment => ({
},
content: comment.content.rendered,
canonical: comment.meta.semantic_linkbacks_canonical,
date: comment.data,
date: comment.date,
});
const comments = async pid => {
const response = await fetch(`https://lewisdale.dev/wp-json/wp/v2/comments?per_page=100&post=${pid}`);
return (await response.json()).map(mapComment);
}
const webmentions = async (pid) => {
const response = await fetch(`https://lewisdale.dev/wp-json/wp/v2/comments?per_page=100&post=${pid}&type=Webmention`, {
headers: {
"Authorization": `Basic ${auth}`
}
});
return (await response.json())
.reduce((comments, comment) => {
if (!comments[comment.meta.semantic_linkbacks_type]) {
comments[comment.meta.semantic_linkbacks_type] = [];
}
comments[comment.meta.semantic_linkbacks_type].push(mapComment(comment));
return comments;
}, { like: [], repost: [] });
}
const getComments = async pid => {
return {
comments: await comments(pid),
...(await webmentions(pid))
}
}
module.exports = async () => {
const response = await fetch("https://lewisdale.dev/wp-json/wp/v2/posts?per_page=100", {
headers: {
"Authorization": `Basic ${auth}`
}
});
const posts = (await response.json());
return Promise.all(posts.map(async post => ({...post, comments: await getComments(post.id) })));
const cache = new PostCache();
await cache.fetchLatest();
return Object.values(cache.posts)
.sort(dateSort)
.map(post => ({
...post,
comments: Object.values(post.comments)
.sort(dateSort)
.reduce((comments, comment) => {
if (!comments[comment.meta.semantic_linkbacks_type]) {
comments[comment.meta.semantic_linkbacks_type] = [];
}
comments[comment.meta.semantic_linkbacks_type].push(mapComment(comment));
return comments;
}, { like: [], reply: [], repost: [] })
}));
};
+6 -1
View File
@@ -9,7 +9,13 @@
<link rel="stylesheet" type="text/css" href="/assets/css/prism.css" />
{% endif %}
<link rel="stylesheet" type="text/css" href="/assets/css/styles.css" />
<link rel="webmention" href="https://lewisdale.dev/wp-json/webmention/1.0/endpoint" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="eleventy" />
<meta name="author" content="{{ metadata.author.name }}" />
<meta name="description" content="{{ description }}" />
</head>
<body>
<header class="wrapper-lg row space-between">
@@ -20,7 +26,6 @@
<li><a href="/">Home</a></li>
<li><a href="/now">Now</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/about">About me</a></li>
</ul>
</nav>
</header>
+58 -2
View File
@@ -3,6 +3,7 @@ layout: base.njk
includePrism: true
eleventyComputed:
title: "{{ post.title.rendered | safe }}"
description: "{{ post.yoast_head_json.description }}"
---
<main class="wrapper-md stack-lg">
<article class="stack-md">
@@ -10,9 +11,64 @@ eleventyComputed:
{{ content | safe }}
</article>
<div class="h-card">
<section class="stack-sm">
<h2>Responses</h2>
{% if post.comments.like | length %}
<div class="stack-xs">
<h3 class="block w-full">Likes</h3>
<div class="row overlaps">
{% for like in post.comments.like %}
<a href="{{ like.author.url }}">
<img src="{{ like.author.avatars["96"] }}" alt="{{ like.author.name }}" class="circle" />
</a>
{% endfor %}
</div>
</div>
{% endif %}
{% if post.comments.repost | length %}
<div class="stack-xs">
<h3 class="block w-full">Reposts</h3>
<div class="row overlaps">
{% for like in post.comments.repost %}
<a href="{{ like.author.url }}">
<img src="{{ like.author.avatars["96"] }}" alt="{{ like.author.name }}" class="circle" />
</a>
{% endfor %}
</div>
</div>
{% endif %}
{% if post.comments.reply | length %}
<div class="stack-xs">
<h3 class="block w-full">Replies</h3>
<ol>
{% for reply in post.comments.reply %}
<li class="row items-center">
<a href="{{ like.author.url }}">
<img src="{{ reply.author.avatars["96"] }}" alt="{{ reply.author.name }}" class="max-w-[4rem] box" />
</a>
<div class="stack-2xs">
{% set date = reply.date | parseDate %}
<h4>{{ reply.author.name }} <span class="font-normal">on</span> {{ date | dateDisplay }} <span class="font-normal">at</span> {{ date | timeDisplay }}</h4>
<a href="{{ reply.canonical }}">Original comment</a>
<p>{{ reply.content | safe }}</p>
</div>
</li>
{% endfor %}
</ol>
</div>
{% endif %}
</section>
<section class="h-card">
<h2>About Lewis</h2>
{% image metadata.author.avatar, "My face", "u-photo box circle", "150px", [150] %}
</div>
</section>
</main>
+14
View File
@@ -0,0 +1,14 @@
.overlaps {
gap: 0;
max-width: 30rem;
padding-left: 1rem;
> * {
display: inline-block;
max-width: 3rem;
}
> * {
margin-inline-start: -1rem;
}
}
+2 -2
View File
@@ -24,8 +24,8 @@ layout: base.njk
<h2>Recent Posts</h2>
<ul class="stack-2xs">
{% for post in collections.posts | reverse | take(3) %}
<li><a href="{{ post.data.url }}">{{ post.data.title }}</a> <time>{{ post.date | dateDisplay }}</time></li>
{% for post in posts | take(3) %}
<li><a href="/post/{{ post.slug }}">{{ post.title.rendered | safe }}</a> <time>{{ post.date | dateDisplay }}</time></li>
{% endfor %}
</ul>