From b5d04b7360de58a2bec7eddc80a56bba346c8fa3 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Thu, 16 Feb 2023 14:10:05 +0000 Subject: [PATCH] Almost done - add replies, webmentions, finish rendering posts from wordpress --- .gitignore | 3 +- config/filters/dates.js | 11 +++ package-lock.json | 26 +++--- package.json | 4 +- src/_data/posts.js | 139 +++++++++++++++++++++++--------- src/_includes/base.njk | 7 +- src/_includes/post.njk | 60 +++++++++++++- src/css/exceptions/overlaps.css | 14 ++++ src/index.html | 4 +- 9 files changed, 208 insertions(+), 60 deletions(-) create mode 100644 src/css/exceptions/overlaps.css diff --git a/.gitignore b/.gitignore index ded7ea9..124bd06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules src/css/custom-props.css _site -.DS_Store \ No newline at end of file +.DS_Store +.cache \ No newline at end of file diff --git a/config/filters/dates.js b/config/filters/dates.js index b4c7cde..88d9e14 100644 --- a/config/filters/dates.js +++ b/config/filters/dates.js @@ -4,4 +4,15 @@ module.exports = function(eleventyConfig) { eleventyConfig.addFilter('dateDisplay', date => new Date(date).toLocaleDateString('en-GB', { "dateStyle": "short" })); + + eleventyConfig.addFilter('dateTimeDisplay', date => new Date(date).toLocaleString('en-GB', { + 'dateStyle': 'short', + 'timeStyle': 'short', + })); + + eleventyConfig.addFilter('timeDisplay', date => new Date(date).toLocaleTimeString('en-GB', { + 'hour': '2-digit', + 'minute': 'numeric', + 'hour12': true + })); } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 52e4361..c10548c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "whimsy", "version": "1.0.0", "license": "ISC", - "dependencies": { - "html-entities": "^2.3.3" - }, "devDependencies": { "@11ty/eleventy": "^2.0.0", "@11ty/eleventy-fetch": "^3.0.0", @@ -19,6 +16,7 @@ "@11ty/eleventy-plugin-syntaxhighlight": "^4.2.0", "@toycode/markdown-it-class": "^1.2.4", "autoprefixer": "^10.4.13", + "lodash": "^4.17.21", "markdown-it-abbr": "^1.0.4", "markdown-it-anchor": "^8.6.6", "markdown-it-eleventy-img": "^0.9.0", @@ -1998,11 +1996,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, "node_modules/html-escaper": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", @@ -2683,6 +2676,12 @@ "node": ">=4" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.chunk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", @@ -6672,11 +6671,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" - }, "html-escaper": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", @@ -7160,6 +7154,12 @@ } } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "lodash.chunk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", diff --git a/package.json b/package.json index 2a17a1c..af2e814 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@11ty/eleventy-plugin-syntaxhighlight": "^4.2.0", "@toycode/markdown-it-class": "^1.2.4", "autoprefixer": "^10.4.13", + "lodash": "^4.17.21", "markdown-it-abbr": "^1.0.4", "markdown-it-anchor": "^8.6.6", "markdown-it-eleventy-img": "^0.9.0", @@ -36,8 +37,5 @@ "postcss-nested": "^6.0.0", "prettier": "^2.8.3", "tailwindcss": "^3.2.4" - }, - "dependencies": { - "html-entities": "^2.3.3" } } diff --git a/src/_data/posts.js b/src/_data/posts.js index e85fed7..9fe46b8 100644 --- a/src/_data/posts.js +++ b/src/_data/posts.js @@ -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: [] }) + })); }; \ No newline at end of file diff --git a/src/_includes/base.njk b/src/_includes/base.njk index 8d52a83..884b6ba 100644 --- a/src/_includes/base.njk +++ b/src/_includes/base.njk @@ -9,7 +9,13 @@ {% endif %} + + + + + +
@@ -20,7 +26,6 @@
  • Home
  • Now
  • Blog
  • -
  • About me
  • diff --git a/src/_includes/post.njk b/src/_includes/post.njk index 380baca..a7d074a 100644 --- a/src/_includes/post.njk +++ b/src/_includes/post.njk @@ -3,6 +3,7 @@ layout: base.njk includePrism: true eleventyComputed: title: "{{ post.title.rendered | safe }}" + description: "{{ post.yoast_head_json.description }}" ---
    @@ -10,9 +11,64 @@ eleventyComputed: {{ content | safe }}
    -
    +
    +

    Responses

    + + {% if post.comments.like | length %} +
    +

    Likes

    + +
    + {% for like in post.comments.like %} + + {{ like.author.name }} + + {% endfor %} +
    +
    + {% endif %} + {% if post.comments.repost | length %} +
    +

    Reposts

    + +
    + {% for like in post.comments.repost %} + + {{ like.author.name }} + + {% endfor %} +
    +
    + {% endif %} + + {% if post.comments.reply | length %} +
    +

    Replies

    + +
      + {% for reply in post.comments.reply %} + +
    1. + + {{ reply.author.name }} + +
      + {% set date = reply.date | parseDate %} +

      {{ reply.author.name }} on {{ date | dateDisplay }} at {{ date | timeDisplay }}

      + Original comment +

      {{ reply.content | safe }}

      +
      +
    2. + {% endfor %} +
    +
    + {% endif %} + +
    +

    About Lewis

    {% image metadata.author.avatar, "My face", "u-photo box circle", "150px", [150] %} -
    + +
    \ No newline at end of file diff --git a/src/css/exceptions/overlaps.css b/src/css/exceptions/overlaps.css new file mode 100644 index 0000000..55ef898 --- /dev/null +++ b/src/css/exceptions/overlaps.css @@ -0,0 +1,14 @@ +.overlaps { + gap: 0; + max-width: 30rem; + padding-left: 1rem; + + > * { + display: inline-block; + max-width: 3rem; + } + + > * { + margin-inline-start: -1rem; + } +} \ No newline at end of file diff --git a/src/index.html b/src/index.html index 6c2af1b..4308b19 100644 --- a/src/index.html +++ b/src/index.html @@ -24,8 +24,8 @@ layout: base.njk

    Recent Posts