From d29d1fbb1b960c996b14abe5349728e9c6addc5c Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 15 Jan 2026 17:39:32 +0000 Subject: [PATCH] Adding some webmentions code --- assets/js/webmentions.js | 121 ++++++++++++++++++++ content/resources/button-generator/index.md | 2 +- {layouts => static}/humans.txt | 3 +- 3 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 assets/js/webmentions.js rename {layouts => static}/humans.txt (83%) diff --git a/assets/js/webmentions.js b/assets/js/webmentions.js new file mode 100644 index 0000000..251791c --- /dev/null +++ b/assets/js/webmentions.js @@ -0,0 +1,121 @@ +/** + * Webmention utilities for ritual.sh + * Fetches and formats webmentions from the API + */ + +class WebmentionUtils { + constructor() { + this.apiUrl = "https://api.ritual.sh"; + } + + /** + * Fetch webmentions for a given target URL + * @param {string} targetUrl - The page URL to get webmentions for + * @param {number} limit - Maximum number of webmentions to fetch (default: 100) + * @returns {Promise} Array of webmention objects + */ + async fetch(targetUrl, limit = 100) { + try { + const params = new URLSearchParams({ + target: targetUrl, + limit: limit.toString(), + }); + + const response = await fetch(`${this.apiUrl}/webmentions?${params}`); + + if (!response.ok) { + console.error(`Webmention API error: ${response.status}`); + return []; + } + + const data = await response.json(); + return data.mentions || []; + } catch (error) { + console.error("Error fetching webmentions:", error); + return []; + } + } + + /** + * Format webmentions as a comma-separated list of links + * @param {Array} mentions - Array of webmention objects + * @returns {string} HTML string of comma-separated links + */ + asCommaSeparatedList(mentions) { + if (!mentions || mentions.length === 0) { + return ""; + } + + return mentions + .map((mention) => { + const url = mention.author_url || mention.source; + const domain = this.formatDomain(url); + const escapedUrl = this.escapeHtml(url); + const escapedDomain = this.escapeHtml(domain); + return `${escapedDomain}`; + }) + .join(", "); + } + + /** + * Format a URL to display just the domain (no protocol, www, or path) + * @param {string} url - The URL to format + * @returns {string} Clean domain name + */ + formatDomain(url) { + if (!url) return ""; + + try { + const urlObj = new URL(url); + let domain = urlObj.hostname; + // Remove www. prefix if present + if (domain.startsWith("www.")) { + domain = domain.substring(4); + } + return domain; + } catch (e) { + // Fallback: strip protocol and www manually + return url + .replace(/^https?:\/\//, "") + .replace(/^www\./, "") + .split("/")[0]; + } + } + + /** + * Escape HTML to prevent XSS + * @param {string} text - Text to escape + * @returns {string} Escaped HTML string + */ + escapeHtml(text) { + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; + } + + /** + * Auto-initialize elements with data-webmention-list attribute + */ + autoInit() { + const elements = document.querySelectorAll("[data-webmention-list]"); + + elements.forEach(async (element) => { + const targetUrl = + element.dataset.webmentionList || window.location.href; + const mentions = await this.fetch(targetUrl); + element.innerHTML = this.asCommaSeparatedList(mentions); + }); + } +} + +// Create global instance +window.WebmentionUtils = new WebmentionUtils(); + +// Auto-initialize on DOM ready +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", () => { + window.WebmentionUtils.autoInit(); + }); +} else { + window.WebmentionUtils.autoInit(); +} diff --git a/content/resources/button-generator/index.md b/content/resources/button-generator/index.md index f17c143..ccb5bee 100644 --- a/content/resources/button-generator/index.md +++ b/content/resources/button-generator/index.md @@ -36,6 +36,6 @@ Big thanks to [neonaut's 88x31 archive](https://neonaut.neocities.org/cyber/88x3 [fyr.io](https://fyr.io/scrap/2026-01-09), [brennan.day](https://brennan.day/resources-for-the-personal-web-a-follow-up-guide/), [kuemmerle.name](https://kuemmerle.name/bastelglueck/), -[craney.uk](https://craney.uk/posts/stuff-this-week-74) +[craney.uk](https://craney.uk/posts/stuff-this-week-74), Am I missing you? Email me or send a webmention! diff --git a/layouts/humans.txt b/static/humans.txt similarity index 83% rename from layouts/humans.txt rename to static/humans.txt index 68c8639..f07f372 100644 --- a/layouts/humans.txt +++ b/static/humans.txt @@ -6,10 +6,9 @@ From: ritual.sh /* THANKS */ Hugo - Static site generator The IndieWeb community -Everyone still making personal websites in {{ now.Year }} +Everyone still making personal websites in 2026 /* SITE */ -Last update: {{ .Lastmod.Format "2006/01/02" }} Standards: HTML5, CSS3, RSS Components: Hugo, YAML, Markdown Software: Built with care