Files
blog-eleventy-indiekit/_data/site.js
Ricardo 910889cde8 fix: remove trailing slash from site.url to prevent double-slash URLs
site.url had a trailing slash (added for Mastodon rel=me verification),
which caused double slashes in all URL constructions like
{{ site.url }}/auth → https://rmendes.net//auth

This broke IndieAuth login — indielogin.com read the authorization_endpoint
link tag with //auth and redirected users there, which 404'd in nginx.

Split into site.url (no slash, for URL construction) and site.me /
site.author.url (with slash, for Mastodon rel=me strict matching).

Also fixed twitter:image meta tags to use smart slash logic matching
the og:image pattern (check if path starts with / before prepending one).
2026-02-24 16:18:52 +01:00

131 lines
5.1 KiB
JavaScript

/**
* Site configuration for Eleventy
*
* Configure via environment variables in Cloudron app settings.
* All values have sensible defaults for initial deployment.
*/
// Parse social links from env (format: "name|url|icon,name|url|icon")
function parseSocialLinks(envVar) {
if (!envVar) return [];
return envVar.split(",").map((link) => {
const [name, url, icon] = link.split("|").map((s) => s.trim());
// Bluesky requires "me atproto" for verification
const rel = url.includes("bsky.app") ? "me atproto" : "me";
return { name, url, rel, icon: icon || name.toLowerCase() };
});
}
// Get fediverse handle for fediverse:creator meta tag
// Prefers the site's own ActivityPub identity over external Mastodon account
function getFediverseCreator() {
// Primary: site's own ActivityPub actor (canonical fediverse identity)
const apHandle = process.env.ACTIVITYPUB_HANDLE;
if (apHandle) {
const domain = (process.env.SITE_URL || "https://example.com").replace(/^https?:\/\//, "");
return `@${apHandle}@${domain}`;
}
// Fallback: external Mastodon account (syndication target)
const instance = process.env.MASTODON_INSTANCE?.replace("https://", "") || "";
const user = process.env.MASTODON_USER || "";
if (instance && user) {
return `@${user}@${instance}`;
}
return "";
}
// Auto-generate social links from feed config when SITE_SOCIAL is not set
function buildSocialFromFeeds() {
const links = [];
const github = process.env.GITHUB_USERNAME;
if (github) {
links.push({ name: "GitHub", url: `https://github.com/${github}`, rel: "me", icon: "github" });
}
const bskyHandle = process.env.BLUESKY_HANDLE;
if (bskyHandle) {
links.push({ name: "Bluesky", url: `https://bsky.app/profile/${bskyHandle}`, rel: "me atproto", icon: "bluesky" });
}
const mastoInstance = process.env.MASTODON_INSTANCE?.replace("https://", "");
const mastoUser = process.env.MASTODON_USER;
if (mastoInstance && mastoUser) {
links.push({ name: "Mastodon", url: `https://${mastoInstance}/@${mastoUser}`, rel: "me", icon: "mastodon" });
}
const linkedin = process.env.LINKEDIN_USERNAME;
if (linkedin) {
links.push({ name: "LinkedIn", url: `https://linkedin.com/in/${linkedin}`, rel: "me", icon: "linkedin" });
}
const apHandle = process.env.ACTIVITYPUB_HANDLE;
if (apHandle) {
const siteUrl = process.env.SITE_URL || "https://example.com";
links.push({ name: "ActivityPub", url: `${siteUrl}/activitypub/users/${apHandle}`, rel: "me", icon: "activitypub" });
}
return links;
}
// site.url: no trailing slash — used as URL base for path concatenation ({{ site.url }}/path)
// site.me / site.author.url: trailing slash — Mastodon rel="me" requires exact match
const siteUrlBase = (process.env.SITE_URL || "https://example.com").replace(/\/$/, "");
const siteUrlWithSlash = siteUrlBase + "/";
export default {
// Basic site info
name: process.env.SITE_NAME || "My IndieWeb Blog",
url: siteUrlBase,
me: siteUrlWithSlash,
locale: process.env.SITE_LOCALE || "en",
description:
process.env.SITE_DESCRIPTION ||
"An IndieWeb-powered blog with Micropub support",
// Author info (shown in h-card, about page, etc.)
author: {
name: process.env.AUTHOR_NAME || "Blog Author",
url: siteUrlWithSlash,
avatar: process.env.AUTHOR_AVATAR || "/images/default-avatar.svg",
title: process.env.AUTHOR_TITLE || "",
bio: process.env.AUTHOR_BIO || "Welcome to my IndieWeb blog.",
location: process.env.AUTHOR_LOCATION || "",
locality: process.env.AUTHOR_LOCALITY || "",
region: process.env.AUTHOR_REGION || "",
country: process.env.AUTHOR_COUNTRY || "",
org: process.env.AUTHOR_ORG || "",
pronoun: process.env.AUTHOR_PRONOUN || "",
categories: process.env.AUTHOR_CATEGORIES?.split(",").map(s => s.trim()) || [],
keyUrl: process.env.AUTHOR_KEY_URL || "",
email: process.env.AUTHOR_EMAIL || "",
},
// Social links (for rel="me" and h-card)
// Set SITE_SOCIAL env var as: "GitHub|https://github.com/user|github,Mastodon|https://mastodon.social/@user|mastodon"
// Falls back to auto-generating from feed config (GITHUB_USERNAME, BLUESKY_HANDLE, etc.)
social: parseSocialLinks(process.env.SITE_SOCIAL).length > 0
? parseSocialLinks(process.env.SITE_SOCIAL)
: buildSocialFromFeeds(),
// Feed integrations (usernames for data fetching)
feeds: {
github: process.env.GITHUB_USERNAME || "",
bluesky: process.env.BLUESKY_HANDLE || "",
mastodon: {
instance: process.env.MASTODON_INSTANCE?.replace("https://", "") || "",
username: process.env.MASTODON_USER || "",
},
},
// Webmentions configuration
webmentions: {
domain: process.env.SITE_URL?.replace("https://", "").replace("http://", "") || "example.com",
},
// Fediverse creator for meta tag (e.g., @rick@rmendes.net)
fediverseCreator: getFediverseCreator(),
// Support/monetization configuration (used in _textcasting JSON Feed extension)
support: {
url: process.env.SUPPORT_URL || null,
stripe: process.env.SUPPORT_STRIPE_URL || null,
lightning: process.env.SUPPORT_LIGHTNING_ADDRESS || null,
paymentPointer: process.env.SUPPORT_PAYMENT_POINTER || null,
},
};