From 299f67f0ad7e5a88a49559606892e7b61e5ae79a Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Wed, 10 Jan 2024 08:27:09 +0000 Subject: [PATCH] Add post about detecing markdown titles --- .../1/detecting-markdown-titles-eleventy.md | 46 +++++++++++++++++++ src/blog/posts/posts.11tydata.js | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/blog/posts/2024/1/detecting-markdown-titles-eleventy.md diff --git a/src/blog/posts/2024/1/detecting-markdown-titles-eleventy.md b/src/blog/posts/2024/1/detecting-markdown-titles-eleventy.md new file mode 100644 index 0000000..3e4126e --- /dev/null +++ b/src/blog/posts/2024/1/detecting-markdown-titles-eleventy.md @@ -0,0 +1,46 @@ +--- +title: Detecting Markdown titles with Eleventy +tags: + - Eleventy + - Obsidian +--- + + +I use [Obsidian](https://obsidian.md) for note-taking, and I'd love to publish those notes somewhere I can easily browse them, personal-wiki style, and ideally I'd want to use [Eleventy](https://11ty.dev) to do it. + +The main blocker is that Obsidian uses file slug/Markdown titles, whereas Eleventy requires the `title` to be set in frontmatter. Obsidian supports adding frontmatter, but it feels weird to have the title set in 2 different places. So here's a quick solution that parses titles out of the document body, and then uses it as the entry title. + +```js +---js +{ + eleventyComputed: { + title: data => { + const fs = require('fs'); + const content = fs.readFileSync(data.page.inputPath, 'utf-8'); + const withoutFrontMatter = content.replace(/^---[^]*---/, ''); + const title = withoutFrontMatter.match(/#{1}\s(.+)/); + return title ? title[1] : 'No title detected :sad:'; + } + } +} +--- +``` + +This is using Javascript frontmatter, using the `eleventyComputed.title` key, we first: +1. Get the contents of the current file, because it's not included in the data passed to the function +2. Strip out the frontmatter using regex +3. Match the first instance of a string that looks like a Markdown heading +4. If it exists, return it. + +This works, but it broke the permalink logic (I was using `permalink: "/post/{{ title | slugify }}`), because the computed values won't have been available at that point. So, I just have to move my permalink into `eleventyComputed`: + +```js +permalink: function(data) { + const title = data.slug ?? data.title; + return `/post/${this.slugify(title)}/` +} +``` + +It works pretty well! There are some obvious flaws, and probably some better approaches. As I've already mentioned, Obsidian uses the Markdown heading for file slugs, so that's also an option (and is discussed in [this Github discussion](https://github.com/11ty/eleventy/discussions/2241)). Also reading in the entire file to get the title is probably not ideal from a performance perspective. + +But, it was early in the morning and nobody was around to stop me. \ No newline at end of file diff --git a/src/blog/posts/posts.11tydata.js b/src/blog/posts/posts.11tydata.js index 52f38ce..d65e2d2 100644 --- a/src/blog/posts/posts.11tydata.js +++ b/src/blog/posts/posts.11tydata.js @@ -1,5 +1,5 @@ module.exports = { tags: ['posts'], layout: 'post.njk', - permalink: "/post/{{ data.slug if data.slug else title | slugify }}/" + permalink: "/post/{{ data.slug if data.slug else title | slugify }}/" } \ No newline at end of file