zettelkasten

Search IconIcon to open search
Dark ModeDark Mode

Publishing Process

#writing/guide #reference

Outdated

This is the publication for the old site that uses Jekyll. The new site now uses Hugo and has a different pipeline.

This note describes my process of building this website and my workflow for publishing content from Obsidian. A frictionless workflow helps to reduce activation energy when publishing notes and reduces work done by friction.

H2 The basics

As mentioned, my markdown notes are written using Obsidian and turned into a static website by Jekyll. All relevant files are stored on Github and the site is hosted by Netlify.

My Jekyll setup is largely based on the Digital Garden Jekyll Template created by Maxime Vaillancourt. The template comes with bidirectional linking support but does not work well with some Obsidian-specific markdown syntax such as highlights, double bracket image embeds, and tags.

To use Obsidian as the markdown editing environment, all I did was opening up my Jekyll directory in obsidian and migrate my Zettelkasten into the _notes folder. Markdown files directly under the _notes directory can be included in the Jekyll with this configuration:

defaults:
  - scope:
      path: "_notes/*.md"
    values:
      layout: "note"
      tags: notes

Attachments are stored under a directory named attachments inside the Jekyll directory.

For publishing control, you might want none of your notes to be published unless you specify published: true in the front matter. This can be achieved by setting published: false as default in _config.yml:

defaults:
  - scope:
      path: "_notes/*.md"
    values:
      layout: "note"
      published: false
      tags: notes

To publish a note, simply apply this front matter:

---
published: true
---

I have also added this meta tag to my HTML template to discourage search engines from indexing my site:

<meta name="robots" content="noindex">

H2 Modifications

H3 Styling tweaks

The default Jekyll syntax highlighter rouge was problematic and fixing it was troublesome, so I replaced it with Prism.

Additional modifications include tweaking the sass files to make things look nicer.

H3 Jekyll plugins

Obsidian-styled latex equations do not get rendered by default, so I configured MathJax to support dollar sign equation syntax. To make things easier, I simply installed the jekyll-spaceship plugin and added this line to Jekyll’s _config.yml:

jekyll-spaceship:
  processors:
    - mathjax-processor
  mathjax-processor:
    src:
      - https://polyfill.io/v3/polyfill.min.js?features=es6
      - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
    config:
      tex:
        inlineMath:
          - ['$','$']
          - ['\(','\)']
        displayMath:
          - ['$$','$$']
          - ['\[','\]']
      svg:
        fontCache: 'global'
    optimize: # optimization on building stage to check and add mathjax scripts
      enabled: false # value `false` for adding to all pages

jekyll-spaceship comes with a mermaid processor but it didn’t work very well for me.

Jekyll’s title from YAML front matter mechanism is not quite my cup of tea since I have H1 headings in my Obsidian markdowns so I have also added the jekyll-titles-from-headings plugin to take care of that with the following configuration:

titles_from_headings:
  enabled:     true
  strip_title: false
  collections: true

H3 Ruby plugins

(I don’t know ruby syntax but my code worked for some meaningless coincidence.)

To make the network graph view from the template display notes’ first heading as title as opposed to Jekyll’s generated title from file name, replace in bidirectional_links_generator.rb:

graph_nodes << {
	id: note_id_from_note(current_note),
	path: "#{site.baseurl}#{current_note.url}#{link_extension}",
	label: current_note.data['title'],
} unless current_note.path.include?('_notes/index.html')

with

graph_nodes << {
	id: note_id_from_note(current_note),
	path: "#{site.baseurl}#{current_note.url}#{link_extension}",
	label: current_note.data['slug'],
} unless current_note.path.include?('_notes/index.html')

To add support for Obsidian highlight, tag pills, and image embeds, I created a new ruby plugin under the _plugins directory. Here’s the code:

class HighlightsGenerator < Jekyll::Generator
  def generate(site)
    all_docs = site.documents
    all_docs.each do |current_note|
      # Fix obsidian image embed
      current_note.content = current_note.content.gsub(
        /\!\[\[(.*)\.(jpg|png|jpeg)\]\]/i,
        '<img src="/attachments/\1.\2" alt="\1.\2">'
      )
      # Fix resized obsidian image embed
      current_note.content = current_note.content.gsub(
        /\!\[\[(.*)\.(jpg|png|jpeg)\|(\d+)\]\]/i,
        '<img src="/attachments/\1.\2" alt="\1.\2">'
      )
      # Fix obsidian highlight
      current_note.content = current_note.content.gsub(
        /\=\=(.*?)\=\=/i,
        '<mark markdown="span">\1</mark>'
      )
      # Replace tag with tag pill
      current_note.content = current_note.content.gsub(
        /(?<=( |\n))#[^\ \n#]+/i,
        '<span class="tag-pill">\&</span>'
      )
    end
  end
end

H2 Publishing process

Simply push the vault to Github, deploy the repository on Netlify, and Netlify will take care of the rest.

H2 Limitations

Regex is great but I haven’t found an easy way to fix things like Obsidian’s inline footnote and note embeds so the current Jekyll site will not pick those up.

The same technique should in theory work for audio embeds so you can try if you need to embed audio files.

Netlify sometimes takes two builds to build a functioning site. I don’t know why this happens but build hook allows you to manually trigger a build. All you need to do is to make a POST request to your build hook URL:

curl -X POST -d '{}' https://api.netlify.com/build_hooks/xxxxxxxxxxxx