Overengineering Simplicity

There are many easy ways to write and publish content. This site is not an example of that.

After trying many techniques over the years, I've settled into markup transformed into HTML. Specifically, I started with Astro, mostly because I've used a lot of static site generators over the years (e.g. Jekyl).

Although I like Markdown, and have used it quite a bit, on a daily basis I use Orgmode in Emacs a lot more. Now, I could just export Orgmode directly to HTML but… no, of course that would be too straightforward. (It's built-in to Orgmode.)

So instead, I am using Pandoc to transform an Orgmode file into Markdown, then I use the markdown file in Astro as an MD or MDX file. But wait, there's more! Recent versions of Astro have a nice content system, and it will leverage front matter in Markdown files for title, publication date, etc. Basically all of the metadata about a post stored in one file. Orgmode has a similar mechanism, however pandoc only copies over certain fields from Orgmode to Markdown. The rest end up as raw blocks in the Markdown, which get rendered in final HTML input and is just totally wrong. But there is a way around it! With a little Lua-based Pandoc filter, you can take all raw blocks and transform them into Metadata. There's even an example in the Pandoc documentation. However, it also includes the unknown Metadata as raw blocks. A one line tweak to their script fixed it.

Victory! So now I'm able to comfortably write my Org files and transform them into Markdown, then build them into the Astro website.

But will I be able to render extra things into the MDX, like React statements? If you can see an embedded YouTube video, it answers is yes!

Update: July 1, 2023

I had originally used some embedded MDX in the source for this page, but it would get mangled on the way through the Orgmode to Markdown to HTML pipeline. I tried wrapping it in \passthrough statements, but that still got mangled, so I ended up hand fixing the markdown.

Today, I got frustrated with the "solution", so I ended up writing a Lua filter that takes links like: yt:abcdef and turns them into the proper iframe that gets passed through to MDX.

Since I can't be bothered to put the code in a Gist, here's the filter I'm using:

-- Really a hack to work around dual markup pipeline <sigh>
function Link(el)
  if el.target:match('yt:(.*)') then
      local target = string.match(el.target, 'yt:(.*)')
      local title = pandoc.utils.stringify(el.content)

      return pandoc.RawInline('html',
               string.format('<iframe ' ..
                             ' class="aspect-video w-full"' ..
                             ' src="https://www.youtube.com/embed/%s"' ..
                             ' title="%s"' ..
                             ' frame-border="0"' ..
                             ' allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"' ..
                             ' allowfullscreen></iframe>', target, title))
  end
end

I've never written Lua before, or it's been years, so there may be a more concise way to do the above. But it gets the job done.