mirror of
https://github.com/svemagie/blog-eleventy-indiekit.git
synced 2026-04-02 16:44:56 +02:00
feat: eliminate URL dualism — computed permalinks, conversations support
- Add computed permalink in data cascade for existing posts without frontmatter permalink (converts file path to Indiekit URL) - Fix ogSlug filter and computed data for new 5-segment URL structure - Add conversations API as build-time data source - Merge conversations + webmentions in webmentionsForUrl filter with deduplication and legacy /content/ URL alias computation - Sidebar widget fetches from both webmention-io and conversations APIs - Update webmention-debug page with conversationMentions parameter
This commit is contained in:
14
_data/conversationMentions.js
Normal file
14
_data/conversationMentions.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import EleventyFetch from "@11ty/eleventy-fetch";
|
||||
|
||||
export default async function () {
|
||||
try {
|
||||
const data = await EleventyFetch(
|
||||
"http://127.0.0.1:8080/conversations/api/mentions?per-page=10000",
|
||||
{ duration: "15m", type: "json" }
|
||||
);
|
||||
return data.children || [];
|
||||
} catch (e) {
|
||||
console.log(`[conversationMentions] API unavailable: ${e.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,55 @@ import { fileURLToPath } from "node:url";
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default {
|
||||
ogSlug: (data) => {
|
||||
const url = data.page?.url;
|
||||
if (!url) return "";
|
||||
return url.replace(/\/$/, "").split("/").pop();
|
||||
},
|
||||
eleventyComputed: {
|
||||
// Compute permalink from file path for posts without explicit frontmatter permalink.
|
||||
// Pattern: content/{type}/{yyyy}-{MM}-{dd}-{slug}.md → /{type}/{yyyy}/{MM}/{dd}/{slug}/
|
||||
permalink: (data) => {
|
||||
// If frontmatter already has permalink, use it (new posts from preset)
|
||||
if (data.permalink) return data.permalink;
|
||||
|
||||
hasOgImage: (data) => {
|
||||
const url = data.page?.url;
|
||||
if (!url) return false;
|
||||
const slug = url.replace(/\/$/, "").split("/").pop();
|
||||
if (!slug) return false;
|
||||
const ogPath = resolve(__dirname, "..", ".cache", "og", `${slug}.png`);
|
||||
return existsSync(ogPath);
|
||||
// Only compute for files matching the dated post pattern
|
||||
const inputPath = data.page?.inputPath || "";
|
||||
const match = inputPath.match(
|
||||
/content\/([^/]+)\/(\d{4})-(\d{2})-(\d{2})-(.+)\.md$/
|
||||
);
|
||||
if (match) {
|
||||
const [, type, year, month, day, slug] = match;
|
||||
return `/${type}/${year}/${month}/${day}/${slug}/`;
|
||||
}
|
||||
|
||||
// For non-matching files (pages, root files), preserve existing permalink or let Eleventy decide
|
||||
return data.permalink;
|
||||
},
|
||||
|
||||
// OG image slug — must reconstruct date-prefixed filename from URL segments.
|
||||
// OG images are generated as {yyyy}-{MM}-{dd}-{slug}.png by lib/og.js.
|
||||
// With new URL structure /type/yyyy/MM/dd/slug/, we reconstruct the filename.
|
||||
ogSlug: (data) => {
|
||||
const url = data.page?.url || "";
|
||||
const segments = url.split("/").filter(Boolean);
|
||||
// Date-based URL: /type/yyyy/MM/dd/slug/ → 5 segments
|
||||
if (segments.length === 5) {
|
||||
const [, year, month, day, slug] = segments;
|
||||
return `${year}-${month}-${day}-${slug}`;
|
||||
}
|
||||
// Fallback: last segment (for pages, legacy URLs)
|
||||
return segments[segments.length - 1] || "";
|
||||
},
|
||||
|
||||
hasOgImage: (data) => {
|
||||
const url = data.page?.url || "";
|
||||
const segments = url.split("/").filter(Boolean);
|
||||
let slug;
|
||||
if (segments.length === 5) {
|
||||
const [, year, month, day, s] = segments;
|
||||
slug = `${year}-${month}-${day}-${s}`;
|
||||
} else {
|
||||
slug = segments[segments.length - 1] || "";
|
||||
}
|
||||
if (!slug) return false;
|
||||
const ogPath = resolve(__dirname, "..", ".cache", "og", `${slug}.png`);
|
||||
return existsSync(ogPath);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user