fix webmentions & css

This commit is contained in:
Kathleen Fitzpatrick
2024-11-29 11:14:42 -05:00
parent d3997cbfb2
commit 891ed350b9
12 changed files with 7431 additions and 82 deletions

BIN
_cache/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,5 @@
import { DateTime } from "luxon";
import sanitizeHtml from 'sanitize-html';
export default function(eleventyConfig) {
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
@@ -6,6 +7,10 @@ export default function(eleventyConfig) {
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy");
});
eleventyConfig.addFilter('dateFromTimestamp', (timestamp) => {
return DateTime.fromISO(timestamp, { zone: 'America/New_York' }).toJSDate()
})
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat('yyyy-LL-dd');
@@ -36,7 +41,7 @@ export default function(eleventyConfig) {
const clean = (entry) => {
const { html, text } = entry.content
if (html) {
entry.content.value = sanitizeHTML(text, allowedHTML)
entry.content.value = sanitizeHtml(text, allowedHTML)
};
return entry;
}
@@ -82,6 +87,7 @@ export default function(eleventyConfig) {
return mentions.filter(entry => !!entry['mentionType'])
});
// Return the smallest number argument
eleventyConfig.addFilter("min", (...numbers) => {
return Math.min.apply(null, numbers);
@@ -97,3 +103,4 @@ export default function(eleventyConfig) {
});
};

View File

@@ -1,95 +1,91 @@
import "dotenv/config.js";
import Fetch from "@11ty/eleventy-fetch";
import 'dotenv/config';
import fs from "fs";
import fetch from "node-fetch";
import unionBy from "lodash-es/unionBy.js";
import domain from "./metadata.js";
// Configuration Parameters
const CACHE_DIR = '_cache';
const API_ORIGIN = 'https://webmention.io/api/mentions.jf2';
const TOKEN = process.env.WEBMENTION_IO_TOKEN;
async function fetchWebmentions(since, perPage = 10000) {
// If we don't have a domain name or token, abort
if (!domain || !TOKEN) {
if (!domain || !TOKEN) {
console.warn('>>> unable to fetch webmentions: missing domain or token');
return false;
}
}
let url = `${API_ORIGIN}?token=${TOKEN}&per-page=${perPage}`;
if (since) url += `&since=${since}`; // only fetch new mentions
const response = await fetch(url);
if (response.ok) {
let feed = await response.json();
console.log(`>>> ${feed.children.length} new webmentions fetched from ${API_ORIGIN}`);
return feed;
}
let url = `${API_ORIGIN}?domain=${domain}&token=${TOKEN}&per-page=${perPage}`;
if (since) url += `&since=${since}`; // only fetch new mentions
const response = await fetch(url);
if (response.ok) {
const feed = await response.json();
console.log(`>>> ${feed.children.length} new webmentions fetched from ${API_ORIGIN}`);
return feed;
}
return null;
return null;
}
// Merge fresh webmentions with cached entries, unique per id
function mergeWebmentions(a, b) {
return unionBy(a.children, b.children, 'wm-id');
return unionBy(a.children, b.children, 'wm-id');
}
// save combined webmentions in cache file
function writeToCache(data) {
const filePath = `${CACHE_DIR}/webmentions.json`;
const fileContent = JSON.stringify(data, null, 2);
const filePath = `${CACHE_DIR}/webmentions.json`;
const fileContent = JSON.stringify(data, null, 2);
// create cache folder if it doesnt exist already
if (!fs.existsSync(CACHE_DIR)) {
// create cache folder if it doesnt exist already
if (!fs.existsSync(CACHE_DIR)) {
fs.mkdirSync(CACHE_DIR);
}
// write data to cache json file
fs.writeFile(filePath, fileContent, err => {
}
// write data to cache json file
fs.writeFile(filePath, fileContent, err => {
if (err) throw err;
console.log(`>>> webmentions cached to ${filePath}`);
});
});
}
// get cache contents from json file
function readFromCache() {
const filePath = `${CACHE_DIR}/webmentions.json`;
const filePath = `${CACHE_DIR}/webmentions.json`;
if (fs.existsSync(filePath)) {
if (fs.existsSync(filePath)) {
const cacheFile = fs.readFileSync(filePath);
return JSON.parse(cacheFile);
};
// no cache found
return {
};
// no cache found
return {
lastFetched: null,
children: []
};
};
}
export default async function() {
console.log('>>> Reading webmentions from cache...');
console.log('>>> Reading webmentions from cache...');
const cache = readFromCache();
const cache = readFromCache();
if (cache.children.length) {
console.log(`>>> ${cache.children.length} webmentions loaded from cache`);
};
if (cache.children.length) {
console.log(`>>> ${cache.children.length} webmentions loaded from cache`);
};
// Only fetch new mentions in production
if (process.env.ELEVENTY_ENV === 'production') {
console.log('>>> Checking for new webmentions...');
// Only fetch new mentions in production
if (process.env.ELEVENTY_ENV === 'production') {
console.log('>>> Checking for new webmentions...');
const feed = await fetchWebmentions(cache.lastFetched);
if (feed) {
const webmentions = {
const webmentions = {
lastFetched: new Date().toISOString(),
children: mergeWebmentions(cache, feed)
}
}
writeToCache(webmentions);
return webmentions;
writeToCache(webmentions);
return webmentions;
}
}
}
return cache;
return cache;
}

View File

@@ -31,7 +31,10 @@
{#- Add an arbitrary string to the bundle #}
{%- css %}/* This is an arbitrary CSS string added to the bundle */{% endcss %}
{#- Add the contents of a file to the bundle #}
{%- css %}{% include "public/css/index.css" %}{% endcss %}
{% css %}{% include "public/css/index.css" %}{% endcss %}
{% css %}{% include "public/css/webmentions.css" %}{% endcss %}
{% css %}{% include "public/css/message-box.css" %}{% endcss %}
{% css %}{% include "public/css/prism-diff.css" %}{% endcss %}
{#- Or you can add from node_modules #}
{# {%- css %}{% include "node_modules/prismjs/themes/prism-okaidia.css" %}{% endcss %} #}

View File

@@ -27,7 +27,8 @@ layout: layouts/base.njk
<hyvor-talk-comments website-id="9100" page-id="{{ permalink }}"></hyvor-talk-comments>
{% include 'webmentionlist.njk' %}
{% include 'webmentions.njk' %}
{%- endif %}
{%- endif %}

View File

@@ -5,37 +5,36 @@
<h4>{{ likes.length }} Like{% if likes.length != 1 %}s{% endif %}</h4>
<div class="webmentions__facepile">
{% for webmention in likes %}
{% if webmention.url != "" %}
<a class="h-card u-url link-u-exempt" href="{{ webmention.url }}" target="_blank" rel="noopener noreferrer">
{% endif %}
{% if webmention.author.photo %}
<img src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" alt="" class="webmentions__face" loading="lazy" />
<img eleventy:ignore class="webmention__author__photo" src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" class="webmentions__face" loading="lazy" />
{% else %}
<img class="webmention__author__photo" src="{{ '/img/default_avatar.png' | url }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" alt="" class="webmentions__face" />
<img eleventy:ignore class="webmention__author__photo" src="{{ '/img/default_avatar.png' | url }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" class="webmentions__face" />
{% endif %}
{% if webmention.url != "" %}
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% if reposts.length > 0 %}
{% if reposts.length > 0 %}
<h4>{{ reposts.length }} Repost{% if reposts.length != 1 %}s{% endif %}</h4>
<div class="webmentions__facepile">
{% for webmention in reposts %}
{% if webmention.url != "" %}
<a class="h-card u-url link-u-exempt" href="{{ webmention.url }}" target="_blank" rel="noopener noreferrer">
{% endif %}
{% if webmention.author.photo %}
<img src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" alt="" class="webmentions__face" loading="lazy" />
<img eleventy:ignore class="webmention__author__photo" src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" class="webmentions__face" loading="lazy" />
{% else %}
<img class="webmention__author__photo" src="{{ '/img/default_avatar.png' | url }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" alt="" class="webmentions__face" />
<img eleventy:ignore class="webmention__author__photo" src="{{ '/img/default_avatar.png' | url }}" alt="{{ webmention.author.name }}" title="{{ webmention.author.name }}" class="webmentions__face" />
{% endif %}
{% if webmention.url != "" %}
</a>

View File

@@ -3,19 +3,19 @@
{% if webmention.author %}
<a class="webmention__author p-author h-card u-url" href="{{ webmention.url }}" target="_blank" rel="noopener noreferrer">
{% if webmention.author.photo %}
<img class="webmention__author__photo u-photo" src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}">
<img eleventy:ignore class="webmention__author__photo u-photo" src="{{ webmention.author.photo }}" alt="{{ webmention.author.name }}">
{% else %}
<img class="webmention__author__photo" src="{{ '/img/webmention-avatar-default.svg' | url }}" alt="">
<img eleventy:ignore class="webmention__author__photo" src="{{ '/blog/img/default_avatar.png' | url }}" alt="">
{% endif %}
<strong class="p-name">{{ webmention.author.name }}</strong>
</a>
{% else %}
<span class="webmention__author">
<img class="webmention__author__photo" src="{{ '/img/webmention-avatar-default.svg' | url }}" alt="">
<img class="webmention__author__photo" src="{{ '/blog/img/default_avatar.png' | url }}" alt="">
<strong>Anonymous</strong>
</span>
{% endif %}
{% if webmention.published %}
<time class="webmention__pubdate dt-published" datetime="{{ webmention.published }}">{{ webmention.published | dateFromTimestamp | readableDate("dd LLL yyyy - HH:mm") }}</time>
{% endif %}
@@ -23,4 +23,4 @@
<div class="webmention__content p-content">
{{ webmention.content.text | safe }}
</div>
</article>
</article>

View File

@@ -1,22 +1,22 @@
{%- set absoluteUrl -%}{{ page.url | url | absoluteUrl(metadata.url) }}{%- endset -%}
{%- set mentions = webmentions.children | mentionsForUrl(absoluteUrl) -%}
<div class="webmentions" id="webmentions">
<h3>Webmentions</h3>
<h3>Webmentions</h3>
{% if mentions | length %}
<h4>{{ mentions.length }} {% if mentions.length == "1" %}Reply{% else %}Replies{% endif %}</h4>
{% if mentions | length %}
<h4>{{ mentions.length }} {% if mentions.length == "1" %}Reply{% else %}Replies{% endif %}</h4>
<ol class="webmentions__list">
{% for webmention in mentions | reverse %}
{% for webmention in mentions | reverse %}
<li class="webmentions__item">
{% include 'webmention.njk' %}
{% include 'webmention.njk' %}
</li>
{% endfor %}
{% endfor %}
</ol>
{% else %}
{% else %}
<p>No replies yet.</p>
{% endif %}
{% endif %}
{% include 'likes.njk' %}
</div>
</div>

View File

@@ -92,9 +92,9 @@ export default async function(eleventyConfig) {
extensions: "html",
// Output formats for each image.
formats: ["jpeg", "png"],
formats: ["jpeg", "png", "webp"],
widths: ["600"],
widths: ["auto", 400, 600],
urlPath: "/img/",
@@ -102,6 +102,7 @@ export default async function(eleventyConfig) {
// e.g. <img loading decoding> assigned on the HTML tag will override these values.
loading: "lazy",
decoding: "async",
sizes: "100vw",
}
});

View File

@@ -4,7 +4,7 @@
"description": "A starter repository for a blog web site using the Eleventy site generator.",
"type": "module",
"scripts": {
"build": "npx @11ty/eleventy --incremental",
"build": "npx @11ty/eleventy --incremental --quiet",
"build-full": "npx @11ty/eleventy",
"build-nocolor": "cross-env NODE_DISABLE_COLORS=1 npx @11ty/eleventy",
"build-ghpages": "npx @11ty/eleventy --pathprefix=/eleventy-base-blog/",
@@ -51,6 +51,7 @@
"@fontsource/atkinson-hyperlegible": "^5.0.3",
"@zachleat/heading-anchors": "^1.0.1",
"dotenv": "^16.3.1",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.21",
"sanitize-html": "^2.13.1"
}
}

View File

@@ -50,4 +50,4 @@
}
.webmention__pubdate {
font-style: italic;
}
}